In the following expression, the result of the left shift operation is assigned to the variable i.

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

In the following expression, the left shift assignment operation is carried.

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

Both the above expressions gave different results. But it's not the same with the following two expressions. Both of them gave the same result. So what could be the reason for the above expressions to return different values?

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

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

There are 3 best solutions below

5
On BEST ANSWER

The C standard says:

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.

So, it is undefined behavior because int is normally 32 bits in size, which means that only 0 through 31 steps are well-defined.

5
On

I agree with Cody Gray's comments. Just for people in future who end up here, the way to resolve this ambiguity is using 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;
14
On

The abstract operational semantics from ISO/IEC 9899 says:

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.

In your case, disassembling and seeing what happens, we see so:

[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)

The generated code tries indeed to shift, but the shll %cl,-0x4(%rbp) (shift left of a long) has no effect.

The undefined behaviour in this case lies in assembly, namely in SHL operation.