Bit manipulation in negative byte and short data types in Java

时光怂恿深爱的人放手 提交于 2020-01-16 20:21:48

问题


Im trying to implement a class that stores a 32-bit number without using the int primitive type. For doing so, I'm using two short variables msbs and lsbs to store the 32 bits of the number, 16 bits in each variable. The variable msbs will store the first 16 bits of the number and the lsbs variable the 16 bits left.

When It comes to save the given bytes to the variables I apply the next formula: (The bytes order are given as Little-Endian notation)

Input -> byte[] n = {0b00110101, -3, 0b1001, 0b0}; to the number 0b00000000 00001001 11111101 00110101 (654645)

msbs = ((n[3] << 8) | n[2]); lsbs = ((n[1] << 8) | n[0]);

As shown below

private void saveNumber(byte[] n) {
    msbs = (byte)((n[3] << 8) | n[2]);
    lsbs = (byte)((n[1] << 8) | n[0]);

    System.out.println(Integer.toBinaryString((n[1] << 8) | n[0]));//Prints 11111111111111111111110100110101

    System.out.println("msbs -> " + Integer.toBinaryString(msbs));
    System.out.println("lsbs -> " + Integer.toBinaryString(lsbs));//Prints 110101
}

The line

System.out.println(Integer.toBinaryString((n[1] << 8) | n[0]));//Prints 11111111111111111111110100110101

prints exactly what I need, despite the huge amount of useless 1's bits at the beggining (of which I can get rid of just by casting it to short) But when I print the lsbs where I store the exact same value (apparently) it outputs 110101 when It should be 0b1111110100110101

Why does this behavior occur? I understand It must be something with the "internal" casting performed by Java at the time of store the value 11111111111111111111110100110101 into a 16 bits primitive type (Which personally, I think sholdn't be happening because I am shifting 8 bits to the left in an 8-bits number which should give me a 16-bits number) As a side note, the msbs variable is doing exactly what I want it to do, so the problem should be related to the way that Java represents the negative numbers

Btw, I know Java isn't exactly the best language to have fun with bits.


回答1:


Why does this behavior occur?

In Java, all bitwise operations are 32 or 64 bit operations. This is different from some other languages, and can be unexpected. But it is what it is.

I understand It must be something with the "internal" casting performed by Java ....

Java doesn't do an implicit narrowing casts in any of your examples1. In fact, I think that the cause of the unexpected behaviour is an explicit narrowing cast in your code:

  msbs = (byte)((n[3] << 8) | n[2]);

You have explicitly cast a 32 bit value from ((n[3] << 8) | n[2]) to a byte. Based on what you say you expect, you should be casting to short.


Aside: When you write things like this "Which personally, I think sholdn't be happening ..." it implies that you are doubting the correctness of the Java compiler. In fact, in 99.999% of cases2, the real problem is someone does not understand what the compiler should do with their; i.e. their knowledge of the language is too shallow3. In most cases, there is a specification of the programming language that says precisely what a particular construct means. In the Java case, it is the Java Language Specification.


1 - In fact the only cases I can think of where internal narrowing happens with primitive types are in the assignment operators.

2 - I made that number up, but the point is that compiler bugs are rarely the cause of unexpected application behaviour.

3 - Or maybe it is just an application bug that the programmer has missed. Tiredness can do bad things to the brain ...



来源:https://stackoverflow.com/questions/32161747/bit-manipulation-in-negative-byte-and-short-data-types-in-java

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