我有一个这样的测试程序:
int main()
{
unsigned n = 32;
printf("ans << 32 = 0x%X\n", (~0x0U) << 32);
printf("ans >> 32 = 0x%X\n", (~0x0U) >> 32);
printf("ans << n(32) = 0x%X\n", (~0x0U) << n);
printf("ans >> n(32) = 0x%X\n", (~0x0U) >> n);
return 0;
}
它产生以下输出:
ans << 32 = 0x0 ... (1)
ans >> 32 = 0x0 ... (2)
ans << n(32) = 0xFFFFFFFF ... (3)
ans >> n(32) = 0xFFFFFFFF ... (4)
我期望(1)和(3)是相同的,以及(2)和(4)是相同的。
使用gcc版本:gcc.real(Ubuntu 4.4.1-4ubuntu9)4.4.1
发生了什么事?
答案 0 :(得分:8)
根据C standard,第6.5.7.3节
,根据类型的大小进行移位是未定义的行为6.5.7按位移位运算符
(...)如果的值 右操作数为负数或大于或等于的宽度 升级后的左操作数,行为未定。
您的编译器应该警告您:
$ gcc shift.c -o shift -Wall
shift.c: In function ‘main’:
shift.c:5:5: warning: left shift count >= width of type [enabled by default]
shift.c:6:5: warning: right shift count >= width of type [enabled by default]
如果你看一下assembler code gcc正在生成,你会发现它实际上是在编译时计算前两个结果。简化为:
main:
movl $0, %esi
call printf
movl $0, %esi
call printf
movl -4(%rbp), %ecx ; -4(%rbp) is n
movl $-1, %esi
sall %cl, %esi ; This ignores all but the 5 lowest bits of %cl/%ecx
call printf
movl -4(%rbp), %ecx
movl $-1, %esi
shrl %cl, %esi
call printf