在以下表达式中,左移操作的结果分配给变量i
。
int i;
i = 7 << 32;
printf("i = %dn",i);
在以下表达式中,进行左移分配操作。
int x = 7;
x <<= 32;
printf("x = %dn",x);
以上表达式给出了不同的结果。但这与以下两个表达式不同。他们俩都给出了相同的结果。那么上述表达式返回不同值的原因是什么?
int a;
a = 1 + 1;
printf("a = %dn",a);
int b = 1;
b += 1;
printf("b = %dn",b);
C标准说:
结果是未定义的如果正确的操作数为负或更大 比左表达式类型中的位数量或等于等位的数量。
因此,它是未定义的行为,因为int
通常是32
位,这意味着只有0
至31
步骤是定义良好的。
我同意科迪·格雷的评论。仅适用于以后最终到达这里的人们,解决这种歧义的方法是长时间使用未签名的方式。
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;
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操作。