直接将左移运算的结果赋值给一个变量和C中的左移赋值运算有什么区别?

What is the difference between directly assigning the result of left shift operation to a variable and the left shift assignment operation in C?

在下面的表达式中,将左移运算的结果赋值给变量i

int i;
i = 7 << 32;
printf("i = %d\n",i);

在下面的表达式中,进行了左移赋值操作

int x = 7;
x <<= 32;
printf("x = %d\n",x);

以上两个表达式给出了不同的结果。但是下面两个表达式就不一样了。他们都给出了相同的结果。那么上述表达式 return 不同值的原因可能是什么?

int a;
a = 1 + 1;
printf("a = %d\n",a);

int b = 1;
b += 1;
printf("b = %d\n",b);

C 标准说:

The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression’s type.

所以,这是 未定义的行为 因为 int 通常是 32 位大小,这意味着只有 031 步骤是 明确定义的

来自 ISO/IEC 9899 的抽象操作语义说:

6.5.7 Bitwise shift operators --- Semantics

3 .... ... . If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

在你的情况下,拆开看看会发生什么,我们是这样看的:

[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    [=11=]x10,%rsp
  4004fe:       c7 45 fc 07 00 00 00    movl   [=11=]x7,-0x4(%rbp)
  400505:       b8 20 00 00 00          mov    [=11=]x20,%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    [=11=]x4005b4,%edi
  400519:       b8 00 00 00 00          mov    [=11=]x0,%eax
  40051e:       e8 cd fe ff ff          callq  4003f0 <printf@plt>
  400523:       b8 00 00 00 00          mov    [=11=]x0,%eax
  400528:       c9                      leaveq 
  400529:       c3                      retq   
  40052a:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

生成的代码确实尝试移位,但 shll %cl,-0x4(%rbp)(long 的左移)没有效果。

本例中的undefined behaviour在于汇编,即在SHL操作中。

我同意 。只是为了未来的人最终来到这里,解决这种歧义的方法是使用 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;