4

I got some C code that confuses me:

int a = 1;
int b = 32;
printf("%d\n %d\n", a<<b, 1<<32);

The output is

1
0

The code was run on Ubuntu 16.04 (Xenial Xerus), and I compiled it using gcc -m32 a.c with GCC version 5.4.0.

I've read some posts that have explained why a<<b outputs 1, but I don't understand why 1<<32 results to 0. I mean, what is the difference between a<<b and 1<<32?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
WilLinG
  • 51
  • 6
  • 3
    The behavior of _undefined behavior_ is undefined. You may get inconsistent results from case to case. – Lundin Oct 16 '17 at 11:37
  • 1
    Why is it always 32? Every time a question like this, it's a shift overflow with UB. Why are developers fixated on 32? If you have 'real' code with huge shifts, stop doing it. – Martin James Oct 16 '17 at 12:18

4 Answers4

6

Shifting a 32-bit int left by 32 is undefined behavior, so any value could be produced as the result. Your C compiler should warn you about it in case of 1<<32 expression.

The reason the two outputs that you see are different is that they are produced by different code paths:

  • a << b uses variables, so it is computed at runtime by the compiled code
  • 1<<32 is a constant expression, so it is computed at compile time by the compiler itself

It looks like the compiled code performs the shift by modulo 32, so shift by 32 is the same as a shift by zero. The compiler itself, however, shifts by 32, dropping the one bit off the end. The compiler is free to do this, because this behavior is undefined. Hence, the standard does not demand any particular behavior, or even a consistent behavior among parts of the same program.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

a<<b and 1<<32 are undefined behaviour, because your right operand is equal to the number of bits.

C11 §6.5.7 Bitwise shift operators

Paragraph 3:

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.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.

Paragraph 4:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

So, if the number is shifted more than the size of integer, the behaviour is undefined.

GCC generated warning:

warning: left shift count >= width of type [-Wshift-count-overflow]
     printf("%d\n%d",a<<b,1<<32);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
msc
  • 33,420
  • 29
  • 119
  • 214
  • so whats the difference between those two statement – krpra Oct 16 '17 at 11:32
  • but the output of `a< – WilLinG Oct 16 '17 at 11:34
  • 1
    both are illegal – 0___________ Oct 16 '17 at 11:34
  • @WilLinG - compilers aren't required to handle undefined behavior any specific way. It's an internal compiler detail that the output is different. Could be different on any other compiler. You can't expect anything from undefined behavior. – Steve Fallows Oct 16 '17 at 11:38
  • because first is a constant expresiion evaluated during the compile time and your complier evaluates it to zero. But because it is an UB any other value will be good as well. if you compile it with -O3 both will be evaluated as zeores. If you do not it will load the uC registers and try to shilt. Most processors ignore shifts longer than the operand size. and you get 1 – 0___________ Oct 16 '17 at 11:39
  • try yourself https://godbolt.org/g/yu3f47 – 0___________ Oct 16 '17 at 11:40
0

Shifting signed values is dangerous and should be avoided.

If the size of the int is 32 bit, 1 << 31 is implementation dependent - two's complement = -2147483648. -1 << 31 gives the same result.

If you shift the value >= times that the number of bits the result is undefined.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0___________
  • 60,014
  • 4
  • 34
  • 74
0

Shifting by a constant value, versus shifting by b bits can result in different behavior under the rule that undefined behavior may be optimized out of existence. In other words, shifting by a constant value is probably optimized differently than shifting by a variable number of bits. Both are obviously undefined behavior so the compiler is free to handle either case any way it wishes. It could literally generate random numbers.

jwdonahue
  • 6,199
  • 2
  • 21
  • 43