在下面的表达式中,左移操作的结果被赋值给变量i
。
int i;
i = 7 << 32;
printf("i = %d\n",i);
在下面的表达式中,执行左移位分配操作。
int x = 7;
x <<= 32;
printf("x = %d\n",x);
上述两种表达都给出了不同的结果。但是以下两个表达式并不相同。两者都给出了相同的结果。那么上述表达式返回不同值的原因是什么呢?
int a;
a = 1 + 1;
printf("a = %d\n",a);
int b = 1;
b += 1;
printf("b = %d\n",b);
答案 0 :(得分:27)
C标准说:
如果右操作数为负数或更大,则结果为未定义 大于或等于左表达式类型中的位数。
因此,它是未定义的行为,因为int
的大小通常为32
位,这意味着只有0
到31
步骤才是的良好定义强>
答案 1 :(得分:5)
我同意Cody Gray's comments。对于将来会在这里结束的人来说,解决这种歧义的方法是使用unsigned long long。
unsigned long long int b = 7ULL<<32; // ULL here is important, as it tells the compiler that the number being shifted is more than 32bit.
unsigned long long int a = 7;
a <<=32;
答案 2 :(得分:1)
来自ISO/IEC 9899
的抽象操作语义说:
6.5.7 Bitwise shift operators --- Semantics
3 ....如果值 右操作数是负数还是大于或等于 提升左操作数的宽度,行为未定义。
在你的情况下,反汇编并看到会发生什么,我们这样看:
[root@arch stub]# objdump -d a.out | sed '/ <main>/,/^$/ !d'
00000000004004f6 <main>:
4004f6: 55 push %rbp
4004f7: 48 89 e5 mov %rsp,%rbp
4004fa: 48 83 ec 10 sub $0x10,%rsp
4004fe: c7 45 fc 07 00 00 00 movl $0x7,-0x4(%rbp)
400505: b8 20 00 00 00 mov $0x20,%eax
40050a: 89 c1 mov %eax,%ecx
40050c: d3 65 fc shll %cl,-0x4(%rbp) <<== HERE IS THE PROBLEM
40050f: 8b 45 fc mov -0x4(%rbp),%eax
400512: 89 c6 mov %eax,%esi
400514: bf b4 05 40 00 mov $0x4005b4,%edi
400519: b8 00 00 00 00 mov $0x0,%eax
40051e: e8 cd fe ff ff callq 4003f0 <printf@plt>
400523: b8 00 00 00 00 mov $0x0,%eax
400528: c9 leaveq
400529: c3 retq
40052a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
生成的代码确实尝试移位,但shll %cl,-0x4(%rbp)
(向左移位)没有效果。
在这种情况下undefined behaviour
位于汇编中,即在SHL操作中。