在以下代码中:
short = ((byte2 << 8) | (byte1 & 0xFF))
目的是&0xFF
什么?因为有时我看到它写成:
short = ((byte2 << 8) | byte1)
这似乎也很好用?
在以下代码中:
short = ((byte2 << 8) | (byte1 & 0xFF))
目的是&0xFF
什么?因为有时我看到它写成:
short = ((byte2 << 8) | byte1)
这似乎也很好用?
将一个整数与0xFF
仅留下最低有效字节。例如,要获取 a 中的第一个字节short s
,您可以编写s & 0xFF
. 这通常称为“掩蔽”。如果byte1
是单字节类型(如uint8_t
)或已经小于 256(因此除最低有效字节外全为零),则无需屏蔽较高位,因为它们已经为零。
当您可能正在使用签名类型时,请参阅下面的tristopia Patrick Schlüter 的回答。在进行按位运算时,我建议只使用无符号类型。
如果byte1
是 8 位整数类型,那么它是没有意义的 - 如果它超过 8 位,它基本上会给你值的最后 8 位:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
& 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
-------------------------------
0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1
byte1
如果类型为is ,则第二个表达式的危险就来了char
。在这种情况下,某些实现可以拥有它signed char
,这将导致在评估时进行符号扩展。
signed char byte1 = 0x80;
signed char byte2 = 0x10;
unsigned short value1 = ((byte2 << 8) | (byte1 & 0xFF));
unsigned short value2 = ((byte2 << 8) | byte1);
printf("value1=%hu %hx\n", value1, value1);
printf("value2=%hu %hx\n", value2, value2);
将打印
value1=4224 1080 right
value2=65408 ff80 wrong!!
我在 Solaris SPARC 64 位的 gcc v3.4.6 上尝试过,结果byte1
与.byte2
char
TL;博士
屏蔽是为了避免隐式符号扩展。
编辑:我检查过,它在 C++ 中的行为相同。
EDIT2:根据要求解释符号扩展。符号扩展是 C 计算表达式方式的结果。C中有一条规则叫做promotion rule。int
在进行评估之前,C 会隐式地将所有小类型转换为。让我们看看我们的表达式会发生什么:
unsigned short value2 = ((byte2 << 8) | byte1);
byte1
是一个包含位模式 0xFF 的变量。如果char
是,则unsigned
该值被解释为 255,如果是signed
,则为 -128。在进行计算时,C 会将值扩展为一个int
大小(通常为 16 或 32 位)。这意味着如果变量是unsigned
并且我们将保留值 255,则该值的位模式int
将是 0x000000FF。如果是,signed
我们想要值 -128,其位模式为 0xFFFFFFFF。该符号被扩展到用于进行计算的临时大小。因此 oring 临时将产生错误的结果。
在 x86 汇编上,它是通过movsx
指令完成的(movzx
对于零扩展)。其他 CPU 有其他指令(6809 有SEX
)。
假设你byte1
是一个字节(8位),当你对一个字节与 0xFF 进行按位与时,你得到的是相同的字节。
所以byte1
是一样的byte1 & 0xFF
说byte1
是01001101
,那么byte1 & 0xFF = 01001101 & 11111111 = 01001101 = byte1
如果 byte1 是其他类型,比如 4 个字节的整数,则与 0xFF 的按位与会留下 byte1 的最低有效字节(8 位)。
这byte1 & 0xff
确保只有 8 个最低有效位byte1
可以是非零。
如果byte1
已经是只有 8 位的无符号类型(例如,char
在某些情况下,或unsigned char
在大多数情况下),它不会有任何区别/完全没有必要。
如果byte1
是带符号的类型或具有超过 8 位的类型(例如 , , short
),并且设置了除 8 个最低有效位之外的任何位,则将存在差异(即,它将在ing之前将那些高位归零与另一个变量,所以这个操作数只影响结果的 8 个最低有效位)。int
long
or
or
它清除所有不在第一个字节中的位
& 0xFF
本身仅确保如果字节长于 8 位(语言标准允许),则忽略其余字节。
这似乎也很好用?
如果结果最终大于SHRT_MAX
,您将获得未定义的行为。在这方面,两者都将同样糟糕。