Why is Java unsigned bit offset for negative byte so strange?

I have a byte variable:

byte varB = (byte) -1; // binary view: 1111 1111 

I want to see the two leftmost bits and make an unsigned right shift of 6 digits:

 varB = (byte) (varB >>> 6); 

But I get -1 , as if it were an int type, and getting 3 only if I switch to 30!

How can I get around this and get the result with only a 6-digit shift?

+5
source share
2 answers

The reason is the expansion of the sign associated with numerical advertising to int , which occurs when the bits are shifted. Before the shift, the value of varB increased to int . An unsigned bit shift to the right occurs, but its effects are discarded when returning to byte , which saves only the last 8 bits:

 varB (byte) : 11111111 promoted to int : 11111111 11111111 11111111 11111111 shift right 6 : 00000011 11111111 11111111 11111111 cast to byte : 11111111 

You can use the bitwise and operator & to mask unwanted bits before wrapping. Bitting with 0xFF contains only the 8 least significant bits.

 varB = (byte) ((varB & 0xFF) >>> 6); 

Here's what is happening now:

 varB (byte) : 11111111 promoted to int : 11111111 11111111 11111111 11111111 bit-and mask : 00000000 00000000 00000000 11111111 shift right 6 : 00000000 00000000 00000000 00000011 cast to byte : 00000011 
+8
source

Because this is how the shift for bytes in java is defined in the language: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19 .

The bottom line is that types smaller than int are gradually expanded to int, shifted, and then narrowed backward.

What makes your single line an effective equivalent:

 byte b = -1; // 1111_1111 int temp = b; // 1111_1111_1111_1111_1111_1111_1111_1111 temp >>>= 6; // 0000_0011_1111_1111_1111_1111_1111_1111 b = (byte) temp; // 1111_1111 

To shift only the byte, you need to explicitly do the advanced conversion using unsigned semantics (and narrowing the conversion should also be manual):

 byte b = -1; // 1111_1111 int temp = b & 0xFF; // 0000_0000_0000_0000_0000_0000_1111_1111 temp >>>= 6; // 0000_0000_0000_0000_0000_0000_0000_0011 b = (byte) temp; // 0000_0011 
+4
source

All Articles