Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java and unsigned values

I'm parsing unsigned bits from a DatagramSocket. I have a total of 24bits (or 3 bytes) coming in - they are: 1 unsigned 8bit integer followed by a 16bit signed integer. But java never stores anything more than a signed byte into a byte/byte array? When java takes in these values, do you lose that last 8th bit?

DatagramSocket serverSocket = new DatagramSocket(666);
        byte[] receiveData = new byte[3]; <--Now at this moment I lost my 8th bit

        System.out.println("Binary Server Listing on Port: "+port);

        while (true)
        {
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(receivePacket);
            byte[] bArray = receivePacket.getData();
            byte b = bArray[0];

        }

enter image description here

Did I now lose this 8th bit since I turned it into a byte? Was it wrong I initialized a byte array of 3 bytes?

like image 998
stackoverflow Avatar asked Jan 02 '13 20:01

stackoverflow


3 Answers

When java takes in these values, do you lose that last 8th bit?

No. You just end up with a negative value when it's set.

So to get a value between 0 and 255, it's simplest to use something like this:

int b = bArray[0] & 0xff;

First the byte is promoted to an int, which will sign extend it, leading to 25 leading 1 bits if the high bit is 1 in the original value. The & 0xff then gets rid of the first 24 bits again :)

like image 148
Jon Skeet Avatar answered Sep 26 '22 01:09

Jon Skeet


No, you do not lose the 8th bit. But unfortunately, Java has two "features" which make it harder than reasonable to deal with such values:

  • all of its primitive types are signed;
  • when "unwrapping" a primitive type to another primitive type with a greater size (for instance, reading a byte to an int as is the case here), the sign bit of the "lower type" is expanded.

Which means that, for instance, if you read byte 0x80, which translates in binary as:

1000 0000

when you read it as an integer, you get:

1111 1111 1111 1111 1111 1111 1000 0000
                              ^
                              This freaking bit gets expanded!

whereas you really wanted:

0000 0000 0000 0000 0000 0000 1000 0000

ie, integer value 128. You therefore MUST mask it:

int b = array[0] & 0xff;

1111 1111 1111 1111 1111 1111 1000 0000 <-- byte read as an int, your original value of b
0000 0000 0000 0000 0000 0000 1111 1111 <-- mask (0xff)
--------------------------------------- <-- anded, give
0000 0000 0000 0000 0000 0000 1000 0000 <-- expected result

Sad, but true.

More generally: if you wish to manipulate a lot of byte-oriented data, I suggest you have a look at ByteBuffer, it can help a lot. But unfortunately, this won't save you from bitmask manipulations, it is just that it makes it easier to read a given quantity of bytes as a time (as primitive types).

like image 41
fge Avatar answered Sep 23 '22 01:09

fge


In Java, byte (as well as short, int and long) is only a signed numeric data types. However, this does not imply any loss of data when treating them as unsigned binary data. As your illustration shows, 10000000 is -128 as a signed decimal number. If you are dealing with binary data, just treat it as its binary form and you will be fine.

like image 42
Code-Apprentice Avatar answered Sep 26 '22 01:09

Code-Apprentice