英文:
What does 0xff <<n do in Java?
问题
从一个输入流(Inputstream)中,我读取了前4个字节并将它们打包,以获取一些信息,即流的大小/长度。
为此,我使用了下面的代码(示例1),这段代码是我从另一个项目中复制过来的。
示例1:使用一个字节数组,从输入流(InputStream)中读取值到名为**in_buf[]**的长度为4的数组中,其值为{0,0,12,26}。
示例1
int size = (((in_buf[0] & 0xff) << 24) | ((in_buf[1] & 0xff) << 16) |
((in_buf[2] & 0xff) << 8) | (in_buf[3] & 0xff)); // 结果是3098
结果就是我得到了大小的值,很好但是...
我需要解释这里发生了什么,
我尝试分割所有的函数,以更好地理解发生了什么并进行调试,我得到了以下的结果:
int byte1 = ((in_buf[0] & 0xff) << 24); // 结果是0
int byte2 = ((in_buf[1] & 0xff) << 16); // 结果是0
int byte3 = ((in_buf[2] & 0xff) << 8); // 结果是3072
int byte4 = (in_buf[3] & 0xff); // 结果是26
然后我推断出,从示例1中,size的结果是0+0+3072+26的和。
但是,这里究竟发生了什么(只有值为12和26)?或者说进行了哪些操作呢?
类似于这样吗?
0000 0000 0000 1100 //12 << 8
0000 1100 0000 0000 // << 8后的结果
为什么我们需要使用掩码 & 0xff 呢?
因为当你调试 int byte3a = (in_buf[3] & 0xff) 时,结果与 int byte3b = in_buf[3] 相同;都是12,其中in_buf[3]的值为12;我在我的调试结果中添加了一张图片。
这里 in_buf[3] & 0xff 发生了什么,类似于?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 1111 0011 ?
英文:
From a Inputstream , i read the first 4 Bytes and packed these to obtain
some information in this case the size/len of the Stream.
For that i use follow code (Example 1) that i copy from another project
Example 1: uses a byte array,where the values are read from InputStream into the array named in_buf[] with lenght 4 and which values are {0,0,12,26}.
Example 1
int size = (((in_buf[0] & 0xff) << 24) | ((in_buf[1] & 0xff) << 16) |
((in_buf[2] & 0xff) << 8) | (in_buf[3] & 0xff)); // result its 3098
and as a result i become the value of the size , nice but..
i need to explain what happens here,
and i try to split all the function to see better what happens and debug , and i become following results
int byte1 = ((in_buf[0] & 0xff) << 24); // result 0
int byte2 = ((in_buf[1] & 0xff) << 16); // result 0
int byte3 = ((in_buf[2] & 0xff) << 8); // result 3072
int byte4 = (in_buf[3] & 0xff); // result 26
then i deduce that from Example 1 the result of size ist the sume of 0+0+3072+26
but what exacly happens (only with value 12 and 26) here? or which operation it's maked?
Something like this ?
0000 0000 0000 1100 //12 << 8
0000 1100 0000 0000 // result after << 8
And why we need use the mask & 0xff ?
cuz when you debug int byte3a = (in_buf[3] & 0xff) the result ist same that int byte3b = in_buf[3]; so 12, *where value of in_buf[3]=12 ; I add a image from my debug results.
What happens or make this in_buf[3] & 0xff , something like?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 1111 0011 ?
答案1
得分: 5
像这样的东西吗?
是的,只是操作数经历了数值提升并转换为int
,所以你应该在技术上展示32位。
为什么我们需要使用掩码
& 0xff
?
这样我们就可以将负字节视为正的int
,基本上就是toUnsignedInt
在做的事情。对于非负字节,它不会产生任何影响,但是对于负字节,比如 -1
:
1111 1111
当由于数值提升而将其转换为int
时,它将被 符号扩展 到32位。也就是说,符号将保持为负数。基本上这意味着如果数字为负数,我们填充1,否则我们填充0。所以 -1
变成了:
1111 1111 1111 1111 1111 1111 1111 1111
现在如果你在此基础上使用 << 8
,将会得到:
1111 1111 1111 1111 1111 1111 0000 0000
这是 -256
。现在让我们看看在执行 & 0xff
之前执行会发生什么。数值提升会发生,将你的字节转换为32个1,就像之前一样,但 & 0xff
只会获取8个最低有效位!因此,现在整数变成了:
0000 0000 0000 0000 0000 0000 1111 1111
这就是你得到原始字节的方式,用0进行填充。然后 << 8
执行明显的操作:
0000 0000 0000 0000 1111 1111 0000 0000
英文:
> some thing like these ?
Yes, except that the operands undergo numeric promotion and turns into an int
, so you should technically show 32 bits.
> and why we need use the mask & 0xff
?
This is so we treat negative bytes as positive ints
, essentially what toUnsignedInt
is doing. It doesn't do anything for non-negative bytes, but for a negative byte, say -1
:
1111 1111
When that gets converted to int
due to numeric promotion, it will be sign-extended to 32-bits. That is, the sign will stay negative. Basically this means that if the number is negative, we pad 1s, otherwise we pad 0s. So -1
becomes:
1111 1111 1111 1111 1111 1111 1111 1111
Now if you use the << 8
on that, it will be:
1111 1111 1111 1111 1111 1111 0000 0000
which is -256
. Now let's see what happens if you do & 0xff
before << 8
. Numeric promotion happens, and converts your byte to 32 ones just like before, but & 0xff
gets only the 8 least significant bits! So the int now becomes:
0000 0000 0000 0000 0000 0000 1111 1111
This is how you get your original byte, padding with 0s. And then << 8
does the obvious thing:
0000 0000 0000 0000 1111 1111 0000 0000
答案2
得分: 2
示例1中的代码获取数组的前四个值(该数组可能包含您描述的“输入流”或其值),并将它们排列到一个变量中,可能是一个足够宽度的(无符号的)整数变量。
这样做是为了获得前四个值的语义含义,根据您未指定的协议。
那么,为什么要以那种“迂回”的方式,使用那些操作符呢?
使用& 0xff
确保仅使用低8位。
在数组中的值来自字节并且仅包含最多位于位7的值的情况下,这是多余的,即不需要的。没有考虑任何较高的位(值为256、512等)。
如果您不相信从流中检索单个字节到数组中的过程。然而,在Java中(如哈罗德在评论中提到的),
& 0xff
在Java中不是多余的,因为字节是有符号类型,因此在转换为整数时会进行符号扩展,并且需要去除这些额外的符号副本。如果字节是无符号的,将节省很多类似这样的代码。
使用<< N
,其中N
是8的倍数,将这八个“收集到的”位移动到结果值内部的位置,从而对结果值产生正确的影响。其中一个字节(我故意不在这里使用“第一个”)属于最低值位置,它没有被移位,其值按原样使用。一个字节被用作较高值的下一个字节,即表示256的倍数(0x100)。依此类推。
使用|
组装正确定位的部分。
那么为什么要以这种复杂的方式做呢?明显的替代方法是将位7以后的所有位都清除,然后将整体视为一个4字节的整数进行读取。
原因是对字节顺序的怀疑。您可能不相信在内存中以某种顺序排列的四个字节,如果作为一个4字节的值读取,将被解释为您在环境中目标的值。这是因为不同的环境可能对最低地址处的字节是表示最低值还是最高值有不同的看法。
所示的代码将选定的字节强制为高值,一个字节为低值,其余字节在中间位置。
英文:
The shown code in example1 takes the first four values of the array (which presumably contains what you describe as "the input stream", or its values). It arranges them into a single variable, presumably an (unsigned) integer one of sufficient width.
It does so in order to get what is presumably the semantic meaning of the first four values, according to a protocol you did not specify.
So, why do so in that "roundabout" way, using those operators?
The use of & 0xff
makes sure that only the lower 8 bit are used.
This is redundant, i.e. unneeded, in case you can rely on the values in the array coming from bytes and hence only containing values up to bit 7. Without any higher bits (valued 256, 512, ...) are taken into account. This makes sense if you do not trust the retrieval of single bytes from the stream into the array.
However in java (as harold kindly pointed out in a comment)
> & 0xff
is not redundant in Java because byte is a signed type, and hence sign-extended when converted to int, and those extra copies of the sign need to be removed. If byte was unsigned it would save a lot of code like this.
The use of << N
, with N
being multiples of 8, moves the eight "harvested" bits into the position inside the result value, where they have the correct influence on the result value. One of the bytes (I intentionally do not use "first" here) belongs into the lowest-valued position, it is not shifted, its value is used as is. One byte is need as the next higher valued byte, i.e. representing multiples of 256 (0x100). And so on.
The use of |
assembles the correctly located parts.
Now why do that in this complicated way? The obvious alternative is to just kill all bits beyond bit 7 and then read the lot as one 4byte integer.
The reason is doubt on endianess. You might not trust that arranging four bytes in a certain order in memory will, if read as one 4byte value, will be interpreted as the value you target in your environment. This is because different environments can be of different opinion whether the byte at the lowest address should be considerd the one representing the lowest values or the highest values.
The shown code forces a selected byte to the high values, one to the low values and the others in between.
答案3
得分: 1
这将强制将值转换为8位字节。
由于Java没有无符号类型,字节值0xFF
被解释为-1
,并且由于Java的特性,它将被提升为32位整数,即0xFFFFFFFF
。
掩码的作用是丢弃负值的那些额外位,以便在使用按位或(|
)位运算符时不覆盖这些位。
以下是一个示例,其中字节值为255
,虽然被解释为-1
并升级为int
:
1111 1111 1111 1111 1111 1111 1111(-1,但原本是无符号字节255)
& 0000 0000 0000 0000 0000 1111 1111(0xff)
----------------------------------
0000 0000 0000 0000 0000 1111 1111(具有原始值255的整数)
英文:
It will force the value into an 8-bit byte.
Since Java has no unsigned types, a byte value of 0xFF
is interpreted as -1
and due to Java's nature it will be promoted to a 32-bit int, i.e. 0xFFFFFFFF
.
The bitmask is meant to discard those extra bits for negative values so they don't overwrite the bits when using the OR bitwise operator |
.
Here's an example with the byte value being 255
, although interpreted as -1
and promoted to int
1111 1111 1111 1111 1111 1111 1111 (-1, but was originally an unsigned byte of 255)
& 0000 0000 0000 0000 0000 1111 1111 (0xff)
----------------------------------
0000 0000 0000 0000 0000 1111 1111 (an int with the original value of 255)
答案4
得分: 1
以下是翻译的内容:
这些是二进制操作。
到底发生了什么?
& 0xFF
基本上意味着,你取最后一个字节。
二进制与(&)意味着,在结果位置上,只有在两个数字在相同位置上都为1时才为1(否则为0)。
这里有另一个例子:
0000 0001 0000 1100 (268)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
12会发生什么?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
移位:
左移只是将位推向左边。
0000 0000 0000 1100 (12)
<< 8
-------------------
0000 1100 0000 0000 (3072)
26会发生什么?
0000 0000 0001 1010 (26)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0001 1010 (26)
为什么我们需要使用掩码 & 0xff?
在这种情况下,你不需要。但是如果你使用更大的数字(或负数),可能需要使用掩码。此外,你确保没有额外的混乱位。
将所有内容与或操作结合起来:
是的,在这种情况下,它基本上是加法。但实际发生的是,你将用 & 0xFF
创建的字节放在一起,以创建一个数字。这就是你通过8的倍数进行移位的原因 - 每个字节都有自己的8位大小的位置。
假设你有字节 X、Y、Z、W。
然后 (X<<24)|(Y<<16)|(Z<<8)|W
将创建一个以二进制形式构建的数字:XYZW
。注意,它不一定是这些数字的总和。
英文:
These are binary operations.
What exactly happens?
the & 0xFF
basically means, you take the last byte.
Binary and (&) means, on the result position will be 1 only if 1 is in both numbers at the same position (0 otherwise).
There is another example:
0000 0001 0000 1100 (268)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
What happens with 12?
0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0000 1100 (12)
shift:
left shift just pushes the bits to the left.
0000 0000 0000 1100 (12)
<< 8
-------------------
0000 1100 0000 0000 (3072)
What happens with 26?
0000 0000 0001 1010 (26)
& 0000 0000 1111 1111 (0xff)
-------------------
0000 0000 0001 1010 (26)
why we need use the mask & 0xff ?
In this case, you don't. But if you worked with larger numbers (or negative numbers), there might be a need to use the mask. Also, you make sure, there are no extra messy bits.
Putting it all together with or:
Yes, it's basically addition, but only in this case. What actually happens is you put the bytes you created with & 0xFF
next to each other to create a number. That is the reason you are shifting by multiplies of 8 - every byte has own place of size 8.
let's say you have bytes X,Y,Z,W.
Then (X<<24)|(Y<<16)|(Z<<8)|W
will create number constructed in binary as followed: XYZW
. Watch out, it doesn't have to be sum of these numbers.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论