I'm a bit confused regarding a conversion from bytes to integers. Consider the following code:
byte[] data = new byte[] { 0, (byte) 0xF0 };
int masked = data[0] << 8 & 0xFF | data[1] & 0xFF; //240
int notMasked = data[0] << 8 | data[1]; //-16
Because bytes in java are signed, data[1] is not 240 decimal, but rather the 2's complement, -16. However, it should still be, in binary: 0x11110000 so, why do I need to do data[1] & 0xFF ?
Is Java converting everything to Integer before passing it to the | operator? Why does &0xFF make a difference then?
Java bytes are signed (unfortunately) - so when you promote the value to an int in order to perform the bitwise |, it ends up being sign-extended as 0xFFFFFFF0. That then messes up the | with data[0]. The masking with & 0xff converts it to an integer value of 240 (just 0x000000F0) instead.
However, you've stlil got a problem. This code:
int masked = data[0] << 8 & 0xFF | data[1] & 0xFF;
should be:
int masked = ((data[0] & 0xff) << 8) | (data[1] & 0xFF);
... otherwise you're masking after the shift, which won't work. I've added brackets because I'm never sure of the predence of &, << and |...
It is similar to a known "puzzle"
byte x = -1;
x = x >>>= 1;
System.out.println(x);
produces
-1
No shift? This is because before compiling arithemtic / shift / comparison expressions javac promotes byte (as well as short and char) to int or to long (if there is any long in the expression), so it works as follows
x -> int = 0xFFFFFFFF; 0xFFFFFFF >>> 1 = 0x7FFFFFF; (byte)0x7FFFFFF -> 0xFF
Related
My goal is to convert 2 bytes to a Char.
The input will be from a byte[] then converted to char. My initial strategy was to use bitwise operations.
My expected result: 0xFF << 8 | 0xFF equals to 0xFFFF. It does. But, in practice it does not because before the bitwise operations, I need to store the data in byte[].
My actual result: Due to the way I access the data. (byte) 0xFF << 8 | (byte) 0xFF will equal to -1.
byte[] bytes = new byte[]{(byte) 0xFF, (byte) 0xFF};
int integer = bytes[0] << 8 | bytes[1]; // -1 or 0xFFFFFFFF
You need:
int integer = (bytes[0] & 0xff) << 8 | (bytes[1] & 0xff);
Which gives the expected value of 65535.
I am unable to figure out the reason for this behavior. I want to left shift by 8 bits the byte value OxAB. Then I want to convert that to a long.
byte oneByte = (byte) 0xAB;
long converted = (oneByte & 0xFF) << 8;
System.out.println(converted);
In this case the output is 43776. However, if I change the code to this:
byte oneByte = (byte) 0xAB;
long converted = (oneByte) << 8;
System.out.println(converted);
The output changes to -21760. I have following questions:
What is the data type of 0xFF?
Why is bitwise AND with 0xFF preventing sign extension?
long converted = onebyte; // gives you -85
and if you shift it 8 times to the left it gives you exactly -21760
because during the conversion to long the left most bit is used as a sign bit.
long converted = onebyte & 0xFF; //gives you 171
and if you shift it 8 times to the left it gives you 43776
because when using the bitwise and byte, short and char are converted to an int first and then the bitwise operation is executed.
11111111111111111111111110101011 //byte 0xAB casted to int
00000000000000000000000011111111 //0xFF is an int literal
00000000000000000000000010101011 //bitwise and operation
after the bitwise and with 0xFF the sign bit is removed
Why when I try to shift bits for 110101002, the result is 1101010002, not 101010002.
int a = Integer.parseInt("11010100", 2) << 1;
I try to do this:
int a = (byte)(Integer.parseInt("11010100", 2) << 1);
But if the output value is greater than 128, everything goes into minus, which is logical.
How can I make that number of bits does not change?
Let's take it one step at a time.
Integer.parseInt("11010100", 2) - this is the int value 212. This is, by the way, needless; you can just write: 0b11010100.
0b11010100 << 1 is the same as 0b110101000, and is 424.
You then cast it to a byte: (byte)(0b11010100 << 1). The bits beyond the first 8 all get lopped off, which leaves 0b10101000, which is -88. Minus, yes, because in java bytes are signed.
You then silently cast this -88 back up to int, as you assign it to an int value. It remains -88, which means all the top bits are all 1s.
Hence, the final value is -88.
If you want to see 168 instead (which is the exact same bits, but shown unsigned instead of signed), the usual trick is to use & 0xFF, which sets all bits except the first 8 to 0, thus guaranteeing a positive number:
byte b = (byte) (0b11010100 << 1);
System.out.println(b); // -88. It is not possible to print 168 when printing a byte.
int asUnsigned = b & 0xFF;
System.out.println(asUnsigned); // 168.
// or in one go:
System.out.println(((byte) (0b11010100 << 1)) & 0xFF); // 168
If you want to set to 0 all bits higher than the bottom 8 bits, you can use bit-wise AND:
int a = (Integer.parseInt("11010100", 2) << 1) & 0xff;
System.out.println (Integer.toString(a,2));
Output:
10101000
Try something like this:
int anInt = Integer.parseInt("11010100", 2) << 1;
int asUnsignedInt= Byte.toUnsignedInt((byte) anInt);
toUnsignedInt has been introduced in Java SE 8.
Ok, so I have searched and searched and nothing worked...
I have this array of int, each int occupies only the low order byte. For instance, I have
data[0] = Ox52
data[1] = Oxe4
data[2] = Ox18
data[3] = Oxcb
I want that the standard output contains exactly those bytes (or in other words, if I write this in a file and I examine the file with a Hex editor, I should see):
52e418cb
How can I do that?
Thank you for your help
The correct way of doing this is to shift the bytes according to their desired position and then stitch them together using the OR operator. But, you should also perform a bit mask on the lower 8 bits of the byte before shifting it. This is needed because a byte is first converted to an int (before the shifting is done). This is no big deal, but when the highest bit is 1 (i.e.: the byte is negative), your integer will become negative as well, which causes all the leading bits to be set on 1.
So:
(byte) 10000000 = (int) 11111111 11111111 11111111 10000000
Using this negative int value with the OR operator will cause a wrong result. So, the working line is this one:
((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16) | ((data[2] & 0xFF) << 8) | (data[3] & 0xFF)
The following seems to work fine. I'm using the OutputStream.write(int) method.
int[] ints = new int[] { 0x52, 0xe4, 0x18, 0xcb };
FileOutputStream os = new FileOutputStream(new File("/tmp/x"));
for (int i : ints) {
os.write(i);
}
os.close();
Results:
> hexdump /tmp/x
0000000 52 e4 18 cb
Just shift and OR them together before writing them to the file/output:
(data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]
I'm trying to convert a short into 2 bytes...and then from those 2 bytes try to get the same short value. For that, I've written this code:
short oldshort = 700;
byte 333= (byte) (oldshort);
byte byte2= (byte) ((oldshort >> 8) & 0xff);
short newshort = (short) ((byte2 << 8) + byte1);
System.out.println(oldshort);
System.out.println(newshort);
For the value of 700 (oldshort), newhosrt is 444. After some testing, it looksl ike \tThis code only works for some values. Like...if oldshort=50, then it will work fine..but if it is -200, or bigger values than 127 (i think) it doesn't work. I guess that there is a problem with the signed bytes, two's complement value, etc...but I can't figure out how to solve it.
Any idea?? Any native way to do this in java?? Thanks in advance!
When recombining, you need to mask the byte1 to stop it being sign extended.
E.g.
short oldshort = 700;
byte byte1= (byte) (oldshort);
byte byte2= (byte) ((oldshort >> 8) & 0xff);
short newshort = (short) ((byte2 << 8) + (byte1&0xFF);
System.out.println(oldshort);
System.out.println(newshort);
EDIT:
All operations on bytes and shorts in java are actually done as integers. So when you write
+byte1, what is really happening is that the byte is first cast to an integer (sign-extended). It will still have the same value, but now has more bits. We can then mask off the bottom 8 bits to get the original 8-bits from the short - without the sign.
E.g. short =511 = 0x01FE
// lots of 0x000's because the operations are done on 32-bit int's
byte1 = (0x000001FE & 0x000000FF) = (0x01FE & 0xFF) = 0xFE = (byte)-2
byte2 = 0x1
newShort = (byte2 << 8) + (byte1 & 0xFF)
= (0x1 << 8) + (0xFE & 0xFF)
// since the ops are performed as int's
= (0x00000001 << 8) + (0xFFFFFFFE & 0x000000FF)
// 0xFFFFFFFE = -2
= (0x00000100) + (0x000000FE)
= 0x000001FE
= 511
You could also use com.google.common.primitives.Shorts, which has methods:
public static byte[] toByteArray(short value)
public static short fromByteArray(byte[] bytes)