Ric*_*III 1 c integer bit-manipulation bit-shift
所以我在C中乱用Bit-Twiddling,我遇到了一个有趣的输出:
int main()
{
int a = 0x00FF00FF;
int b = 0xFFFF0000;
int res = (~b & a);
printf("%.8X\n", (res << 8) | (b >> 24));
}
Run Code Online (Sandbox Code Playgroud)
此声明的输出是:
FFFFFFFF
我期待输出
0000FFFF
但为什么不是呢?我在这里错过了一些比特移位的东西吗?
TLDR:你的整数b是负数,所以当你向右移动时,最高位(即1)的值保持不变.因此,当你将b向右移动24个位置时,你最终会得到0xFFFFFFFF.
更长的解释:
假设在您的平台上,您的整数是32位或更长,并且有符号整数由2的补码表示,则分配给有符号整数变量的0xFFFF0000是负数.如果int超过32位,则0xFFFF0000将首先进行符号扩展,但仍为负数.
向右移动负数是由标准定义的实现(C99/N1256,第6.5.7.5节):
E1 >> E2的结果是E1右移E2位位置.[...]如果E1具有带符号类型和负值,则结果值是实现定义的.
这意味着特定的编译器可以选择在特定情况下发生的情况,但应在编译器手册中注明效果是什么.
在许多处理器中往往有两组移位指令,即逻辑移位和算术移位.逻辑右移将移位,并用零填充暴露的位.算术右移(假设再次为2的补码)将使用最高有效位的相同位值填充暴露的位,以使其结果与使用移位除以2的结果一致.(例如,-4 >> 1 == 0xFFFFFFFC >> 1 == 0xFFFFFFFE == -2.)
在您的情况下,似乎编译器实现者在应用于有符号整数时选择使用算术移位,因此将负值向右移动的结果仍为负值.在位模式方面,0xFFFF0000 >> 24给出0xFFFFFFFF.
除非你完全确定你在做什么,否则最好只对无符号类型执行按位运算,因为它们的内部表示可以安全地被视为一个位集合.您可能还希望确保在这种情况下使用的任何数值都是无符号的,方法是将无符号后缀附加到您的数字上.