Reputation: 71
Is there a way to read two bytes as a signed integer?
Given two bytes in java, each represents an integer, we can convert them to the int value they represent together by simply:
byte[] byteArray = new byte[4];
byteArray[0] = 0x00;
byteArray[1] = 0x00;
byteArray[2] = .. //a byte representing an integer
byteArray[3] = .. //a byte representing an integer
int i = ((byteArray[2] & 0xff) << 8) | (byteArray[3] & 0xff);
It works perfectly when the two bits represent positive integers. But it fails when the two integers are negative. For example when:
byteArray[2] = 0xff; // -1
byteArray[3] = 0xf9; // -7
I get:
i = 65529;
which is incorrect. It should just be -8 which is 0xf8.
I tried using ByteBuffer:
byte[] array = new byte[4];
array[0] = 0x00;
array[1] = 0x00;
array[2] = 0xff;
array[3] = 0xf9;
ByteBuffer buffer = ByteBuffer.wrap(array);
int i = buffer.getInt();
Didn't work. Got the same result:
i = 65529
Those are only examples. There will be more bytes and they will be representing positive and negative integers.
Is there a way to read two bytes as a signed integer and get the correct result?
Thanks in advance.
Upvotes: 2
Views: 4188
Reputation: 2336
kotlin way
val low: UByte = bytes[3].toUByte()
val high: UByte = bytes[4].toUByte()
return (high.toInt() shl 8) or low.toInt()
Upvotes: 0
Reputation: 37835
In your case, you can just remove the bitwise &
from the high byte:
int i = (byteArray[2] << 8) | (byteArray[3] & 0xff);
& 0xff
was undoing the sign extension that you wanted. You still need it on the low byte.
Two's complement sign extension works like this:
If the most-significant bit of the smaller size number is set,
// v
0b1000000_00000000
Fill the new bits above the old most-significant bit with 1s:
// vvvvvvvv vvvvvvvv
0b11111111_11111111_1000000_00000000
Java does it automatically any time a byte
or short
is converted to int
or long
, and the purpose of & 0xFF
on a byte
is to undo the automatic sign extension.
If you didn't have access to the bytes, you could do sign extension yourself using the arithmetic right-shift:
i = (i << 16) >> 16;
Or casting to a short
:
i = (short) i;
Or a variety of if
tests such as:
if ((i & 0x80_00) != 0) // Is the MSB of the high byte set?
i |= 0xFF_FF_00_00; // Fill the rest with 1s.
And:
if (i > 32767)
i -= 65536;
Upvotes: 3
Reputation: 1155
Two bytes as a signed integer:
public class MyClass {
public static void main(String args[]) {
byte h = (byte)0xff;
byte l = (byte)0xf9;
int i = (short) ((h << 8) | l);
System.out.println(i);
}
}
(I'll paste the comment I made under your question here):
Use a short
instead, because the leftmost bit of your int
is 0, therefore it is a positive number. But if you use a short
, then you'll get the negative value you want, because the type short
only have 2 bytes, then the leftmost bit will be the leftmost 1 in 0xFF, making it a negative number.
Upvotes: 2