convert byte to int using bit wise opertators

1

I'm documenting some code in Java. Before I ask my quetion I'll give you guys some background info. The goal is to read and process an orsm file which is a file containing hex codes.

The flow is as follows: Read in some byte to a ByteBuffer using a FileChannel. Once the buffer is filled, convert every byte to a signed integer. This is done using the bitwise & operator and the signed left shift operator <<, and looks like this:

return  (0x000000ff & (bb.get() << 0)) |
        (0x0000ff00 & (bb.get() << 8)) |
        (0x00ff0000 & (bb.get() << 16)) |
        (0xff000000 & (bb.get() << 24));

Where bb is of course the ByteBuffer. I have totaly no clue how and why this code works, I Googled a bit and the closest thing I found was the following Stack Overflow question: Converting java method to C#: converting bytes to integers with bit shift operators. Still I have no clue and I'm wondering if someone could help me figure out this code snippet?

java
int
bit-manipulation
byte
bytebuffer
asked on Stack Overflow Feb 18, 2015 by jorne • edited Nov 25, 2019 by Jonny Henly

2 Answers

7

This reads four bytes from the underlying byte buffer and stitches them together into an int value like this:

                        11111111 (first byte read)
                22222222         (second byte read)
        33333333                 (third byte read)
44444444                         (fourth byte read)

To achieve that, a bitwise OR operation is performed on all subresults, where each subresult prepares one row in the above diagram. For example, the third row is prepared as

(0x00ff0000 & (bb.get() << 16))

which does the following:

  1. read the byte:

    xxxxxxxx
    
  2. expand the byte into an int:

    000000000000000000000000xxxxxxxx        
    
  3. shift the bits to the left by 16 slots:

    00000000xxxxxxxx0000000000000000
    
  4. finally, push this through an AND mask which lets only the x bits through. This is needed because byte is signed, so the conversion to int may actually result in the following:

    111111111111111111111111xxxxxxxx
    

The code would perhaps be simpler if a constant AND-mask was performed before shifting:

(bb.get() & 0xFF) << 16

This is actually the standard idiom for Java in these bit-twiddling operations.


Although not an answer to the question you have asked, using the provided API would certainly be preferred (the getInt method). Your byte order is little endian, so you would just need to set it up:

bb.order(ByteOrder.LITTLE_ENDIAN);

For reference, this is the JDK's implementation of the same code:

static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
    return (((b3       ) << 24) |
            ((b2 & 0xff) << 16) |
            ((b1 & 0xff) <<  8) |
            ((b0 & 0xff)      ));
}
answered on Stack Overflow Feb 18, 2015 by Marko Topolnik • edited Feb 18, 2015 by Marko Topolnik
0

Basically, it reads in four bytes, each of which is eight bits and it combines them together into an integer which is 32 bits. It does this by shifting each successive byte an extra 8 places to the left, so the first byte read is placed into the last (lowest order) 8 bits of the integer (0-7); the next byte goes into the next 8 bits (15-8), etc.

It would be a lot easier to use the actual functionality of the ByteBuffer to do this though:

bb.order(ByteOrder.LITTLE_ENDIAN); // Called once on the buffer
int intFromNextFourBytes = bb.getInt(); // Read the same value as your code.
answered on Stack Overflow Feb 18, 2015 by BarrySW19

User contributions licensed under CC BY-SA 3.0