Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java shift right outputting negative value

Tags:

java

i'm really confused with, well it's best if I show my code first so here's what I got.

void dumpInt(int x) throws IOException {
    if ( true ) {
        //8388638
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        writer.writeByte(x&0xff);
        writer.writeByte((x>>8)&0xff);
        writer.writeByte((x >> 16) & 0xfff);
        writer.writeByte((x>>24)&0xff);
        outputStream.write(x & 0xff);
        outputStream.write((x >> 8) & 0xff);
        outputStream.write((x >> 16) & 0xff);
        outputStream.write((x >> 24) & 0xff);
        System.out.println((x >> 16) & 0xff);
        if(x == 8388638){
            String xz = "";
            byte[]array = outputStream.toByteArray();
            System.out.println(array[2]+" | " + (char)array[2]);
        }
    } else {
        writer.writeInt(x);
    }
}

this works fine but when I do dumpInt(8388638), I get some weird occurrences. writer.writeByte((x >> 16) & 0xfff) writes -128 to the writer Im clueless as why that is.

The same thing happens for outputStream.write((x >> 16) & 0xff); but when I run System.out.println((x >> 16) & 0xff); it outputs 128(positive)

Does anybody know why this is and how I can correct it? (Sorry i'm somewhat experienced in java but im not the best by any means so if this is a really simple fix my bad)

like image 964
Anonymouss121 Avatar asked Dec 02 '25 11:12

Anonymouss121


1 Answers

Bytes in Java are signed, and have the range -128~127. You seem to be more familiar with the other decimal representation of a byte - the unsigned byte, having a range from 0 to 255. However, that doesn't exist in Java as a separate data type.

The following shows corresponding values between the two representations:

  signed    -128 -127 -126 ... -1   0   1   ...   126 127 128
unsigned    128  129  130  ... 255  0   1   ...   126 127 128

Note: these are not really different representations in binary. They have the same binary representation. It depends on whether you interpret the MSB as the sign bit or not.

You can convert from the signed version to the unsigned version by Byte.toUnsignedInt, and you can convert from the unsigned version to the signed version by casting to byte.

For some reason that you'd have to ask the API designers, OutputStream.write accepts unsigned bytes (as well as signed ones). How does Java do this if byte only ranges from -128 to 127? It accepts an int rather than a byte! This is the reason why your code compiles at all.

write (which writeByte also calls) converts the int 128 to a (signed) byte -128 and writes it into the stream. When you get the written bytes later, you are getting the converted signed byte. But in fact, in terms of the bits, 128 and -128 are the same 1000 0000. It's just that Java insists on interpreting the first 1 as a sign bit.

As I said before, you can convert the -128 to 128` if you prefer the other representation:

Byte.toUnsignedInt(-128) // 128

Note that the result must be an int, because the result is outside of byte's range.

like image 65
Sweeper Avatar answered Dec 04 '25 01:12

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!