short = ((byte2 << 8) | (byte1 & 0xFF))
& 0xFF
的目的是什么?因为有时候,我看到上面的代码被写成:
short = ((byte2 << 8) | byte1)
而且这似乎也很好地运作着。
short = ((byte2 << 8) | (byte1 & 0xFF))
& 0xFF
的目的是什么?因为有时候,我看到上面的代码被写成:
short = ((byte2 << 8) | byte1)
如果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
将整数与 0xFF
相与可以得到最低有效字节,例如,要获取 short s
中的第一个字节,您可以编写 s & 0xFF
。这通常被称为“掩码”。如果 byte1
是单个字节类型(如 uint8_t
)或已经小于256(结果全部是零,除了最低有效字节),则无需屏蔽高位,因为它们已经是零。
在可能使用有符号类型时,请参见 tristopia Patrick Schlüter 的下面的答案。在进行位运算时,我建议仅使用无符号类型。
第二个表达式的危险在于,如果byte1
的类型是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
相同。
太长不看:
掩码是为了避免隐式符号扩展。
编辑:我检查了一下,在C++中的行为是相同的。
编辑2:根据要求解释符号扩展。符号扩展是C评估表达式的方式所导致的后果。C中有一个叫做promotion rule的规则。在进行评估之前,C将隐式地将所有小类型转换为int
。让我们看看我们的表达式会发生什么:
unsigned short value2 = ((byte2 << 8) | byte1);
byte1
是一个包含位模式0xFF的变量。如果char
是unsigned
,那么该值将被解释为255;如果它是signed
,则为-1。在进行计算时,C会将该值扩展到int
大小(通常为16或32位)。这意味着,如果变量是unsigned
,并且我们将保留值255,则该值的位模式作为int
将为0x000000FF。如果它是signed
,我们想要的值是-1,其位模式为0xFFFFFFFF。符号被扩展到用于执行计算的临时大小。
在x86汇编中,可以使用movsx
指令(对于零扩展,使用movzx
)。其他CPU有其他指令(6809有SEX
)。
byte1
是一个字节(8位),当您对一个字节与0xFF进行按位AND时,您得到的是相同的字节。byte1
与byte1&0xFF
是相同的。byte1
是01001101
,那么byte1&0xFF = 01001101&11111111 = 01001101 = byte1
如果byte1
属于其他类型,如4字节整数,则按位AND与0xFF会留下字节1的最低有效字节(8位)。byte1 & 0xff
确保只有 byte1
的最低有效位是非零的。byte1
已经是一个只有8位的无符号类型(例如某些情况下的 char
或大多数情况下的 unsigned char
),那么这行代码不会有任何影响/完全没有必要。byte1
是一个带符号或者超过8位的类型(例如 short
,int
,long
),并且除了最低的8位之外的任何一位都被设置了,那么就会有所不同(也就是说,在与其他变量进行“或”运算之前,它将清除那些上面的位,因此这个操作数仅影响结果的最低有效位)。byte1
的类型是 char
或 signed char
,那么这是绝对必要的。 - Patrick Schlüter它清除了除第一个字节外的所有位
& 0xFF
可以确保如果字节长度超过了 8 位(语言标准允许),则其余部分将被忽略。
如果结果大于这似乎也很好用?
SHRT_MAX
,你将得到未定义的行为。在这方面,两者都一样糟糕。
uint8_t
类型吗? - Shahbazbyte1
的类型被更改,因为byte2
已经不是8位了(否则byte2 << 8
就是0)。 - Shahbazbyte2
是8位类型,byte2 << 8
也可以工作。默认情况下,表达式总是作为int
工作的。编译器会隐式地将表达式视为((int)byte2) << ((int)8)
。 - Patrick Schlütershort
是一个保留字,不能用作变量名。 - Patrick Schlüter