8

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?

5
  • 1
    I would love to have unsigned variables (not only char) would make some code easier and would allow the compiler to make some optimization, only valid for unsigned values. Commented Jan 2, 2013 at 20:59
  • @MrSmith The compiler can do whatever it needs to do, as all operations on signed values are well-defined in Java. Commented Jan 9, 2013 at 13:06
  • @starblue: I mean for unsigned values some optimizations are allowed, which are not allowed for signed values. E.g a % 4 can be optimized ti a & 2 that is only valid for positive numbers. => a javacompiler is not allowed to do this optimization, even if the developer only uses positive numbers. Commented Jan 9, 2013 at 13:09
  • 1
    @MrSmith You are right, unsigned division is one of the few things that is not easily emulated with operations on signed numbers. Java 8 will fix that by adding the missing operations for unsigned numbers: blogs.oracle.com/darcy/entry/unsigned_api Commented Jan 10, 2013 at 9:41
  • stackoverflow.com/questions/397867/… Commented Jan 10, 2013 at 9:44

3 Answers 3

12

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

Sign up to request clarification or add additional context in comments.

7 Comments

If space is an issue, you don't have to convert to an int. You can still use byte and treat it as binary data.
@Code-Guru could you demonstrate this. Thank you for your response
@stackoverflow: It's hard to demonstrate it without knowing what you're trying to do with the value. But the data itself would indeed be safe.
@stackoverflow I'm not sure what you want me to demonstrate. The data in a byte is binary bits. It's more about how you think about the data than about how the computer actually stores it.
@stackoverflow see my answer. I have done quite a bit of manipulation on unsigned values (by processing network packets where unsigned values are common) and I have figured out what is really happening. And it is not pretty...
|
9

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 Comments

Very helpful and informative with your demonstration. I greatly appreciate your response
@stackoverflow except that I coded an int on 16 bits whereas it is 32 :) Fixed, but the principle stays the same.
Yeah I noticed but I got what you were trying to say. thanks again
2

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.

4 Comments

By the way: charis an unsigned datatype
@MrSmith42 Thanks for the catch. I qualified my statement to hopefully be more accurate.
char is a numeric unsigned data type with values 0 .. 65535 . But I think it should not be used as a general purpose numeric type.
@MrSmith42 I was trying to avoid wordiness and possibly leaving out applicable types. Hopefully my newest edit is more accurate. What do you think?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.