Java and unsigned values

亡梦爱人 提交于 2019-11-29 14:03:38

问题


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];

        }

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?


回答1:


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 :)




回答2:


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).




回答3:


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.



来源:https://stackoverflow.com/questions/14129017/java-and-unsigned-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!