将左移动操作的结果直接分配到变量与C中的左移位分配操作之间有什么区别



在以下表达式中,左移操作的结果分配给变量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位,这意味着只有031步骤是定义良好的

我同意科迪·格雷的评论。仅适用于以后最终到达这里的人们,解决这种歧义的方法是长时间使用未签名的方式。

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操作。

相关内容

  • 没有找到相关文章

最新更新