Java: Bitshifting bytes

Written on April 29, 2015

TL;DR When bitshifting a `byte` use a `& 0xFF` mask

Working at the bit level in Java can be very frustrating. This is for two reasons

1. There are no unsigned number primitives
2. Automatic type promotion is not intuitive!

Looking at type promotion, whenever you use a bitwise operator on a `byte` variable it is automatically promoted to an `int`.

This means you have to write casting code such as

`byte b = (byte) (b ^ 8);` or `b ^= 8` which does the former under-the-hood.

This is not too bad really. But the pain starts when working with signed numbers together with `int` promotion. For example

ex1.java

For `bByte` we would expect the result to be `0b1111_1001` as the right Arithmetic shift operator `>>` fills the left bit depending on the left most (sign) bit (which is `1` when negative ala 2’s complement) so the result is as expected.

However for `cByte` we would expect the result to be `0b0000_1001` as the right Logical shift operator `>>>` should fill the left most bit with `0`, but we still get `-7`! Why is this happening?

Well due to the auto int promotion (as a result of using any bitwise operator), when the `aByte` is promoted to an `int`, the left most bits of that int are all `1`s. In binary form this is

`0b1111_1111_1111_1111_1111_1111_1001_0000` before the shift

`0b0000_1111_1111_1111_1111_1111_1111_1001` after the shift

Due to how casting works when casting down the last 8-bits will be copied directly, hence still giving `0b1111_1001`. Not very intuitive when you see `aByte >>> 4` imho.

So how can we perform `>>>` operations and get the “intuitive” result of `0b0000_1001`?

Note: This is useful as to be able to do as Java does not have an unsigned byte type the above kind of operation would let you use a java `byte` in place of another languages `unsigned byte` type. This can useful when porting code, for example, if you want to replicate a `ubyte >> 4` call then the below will be useful.

The answer is to mask the bitwise result before casting back down to `byte`. We can do this with `& 0xFF`. This works by persevering only the last 8 bits of the promotioned-to `int` only, and dropping all the extra `1` bits.When casting down we then get the result we are looking for. I.e.

ex2.java

This is a bit clunky but a valuable technique if you are encountering unexpected results from your bitshifts!