0

I am currently experimenting with bitwise operations in C and I am trying to understand why this code prints a different value for variable a and variable b. I know that a 32 bit shift overflows the 1 variable (that is a normal int), but my understanding is that it should print 0 in both cases.

Instead, it prints what seems like a random number with the unsigned int a and a 0 value with the unsigned long int b.

#include <stdio.h>

int main(){
  printf("%lu %lu\n",sizeof(int), sizeof(long int));
  unsigned int a = 1 << 32;
  unsigned long int b = 1 << 32;
  printf("%u %lu\n", a, b);
  return 0;
}

Sample output:

4 8
374588997 0

What am I missing?

EDIT

Now I am trying only with a 31 bit shift, the compiler gives me NO warning. Source:

#include <stdio.h>

int main(){
  int shift = 31;
  unsigned long int b = 1 << shift;
  printf("%lu\n", b);
  return 0;
}

And it outputs 18446744071562067968, that is really not 2^31. Any clue?

Luke Morgan
  • 1,900
  • 2
  • 14
  • 18
  • 2
    If is [undefined behavior is the shift size is greater or equal to the bit length](https://stackoverflow.com/questions/19636539/arithmetic-right-shift-gives-bogus-result/19636588#19636588). – Shafik Yaghmour May 02 '14 at 09:36
  • Ok, but why does it give a different result between the two operations? The expression is still the same: 1 << 32, the LHS changes but the expression should be already evaluated. – Luke Morgan May 02 '14 at 09:38
  • Because nasal demons. http://www.catb.org/jargon/html/N/nasal-demons.html – thejh May 02 '14 at 09:39
  • Mmmmm... where did you get your hands on a compiler that yields `sizeof(long int) == 8`? – barak manos May 02 '14 at 09:45
  • Also see: http://stackoverflow.com/questions/7401888/why-doesnt-left-bit-shift-for-32-bit-integers-work-as-expected-when-used – P.P May 02 '14 at 09:47
  • Check the disassembly of the line `unsigned int a = 1 << 32`, and you'll get an answer to your question. Microsoft Visual C++ 2010 compiler yields `mov dword ptr [a],0`, which means that variable `a` is set to 0. I cannot check it on your `OS X - llvm/clang` platform, since I don't have it installed. Based on your print results, my guess is that the compiler ignores this assignment, leaving variable `a` uninitialized. – barak manos May 02 '14 at 09:52

3 Answers3

0

First a is random because the shift count is greater than the length of the type. This is undefined behavior:

/tmp/test.c: In function 'main':
/tmp/test.c:5:6: warning: left shift count >= width of type [enabled by default]
      unsigned int a = 1 << 32;
      ^

Now b is declared as long int, but its value is computed with 32 bit logic, since by default 1 is int:

/tmp/test.c:6:8: warning: left shift count >= width of type [enabled by default]
      unsigned long int b = 1 << 32;
      ^

The correct expression for b would be:

unsigned long int b = 1L << 32;

EDIT to answer your new question:

In C, 1 is by default signed int therefore 1 << 31 is the negative number -2147483648. Now this number gets converted to 64 bits, it becomes 0xffffffff80000000 (-2147483648 as signed long int) and finally its signedness is discarded. That's why you get 18446744071562067968 which is 0xffffffff80000000.

Grapsus
  • 2,714
  • 15
  • 14
0

Change your code as below

#include <stdio.h>

int main(){
  int shift = 31;
  unsigned long int b = 1LU << shift; /* or 1U << shift */
  printf("%lu\n", b);
  return 0;
}

It seems on your system long int is 64 bit.

You are getting int result which is negative and trying to store it into 64 bit unsigned leading to the strange number.

p.s. 18446744071562067968 = FFFFFFFF80000000

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • @ShafikYaghmour Thank you for your expert comment. Can you please shed more light why it is undefined? I have read many knowledge sharing posts from you. And a brief comment/explanation here would benefit both OP and me. – Mohit Jain May 02 '14 at 11:52
  • Your explanation of the problem is incomplete, I linked an explanation in my [comment above](http://stackoverflow.com/questions/23424985/behavior-with-c-bitwise-operations/23425138#comment35898968_23424985). Your example code is ok since you are only shifting by `31` but you need to explain that the results of undefined behavior are unreliable and although they can be explain on a specific instance it is not a general explanation. – Shafik Yaghmour May 02 '14 at 11:58
  • Note that `clang` generates some useful error message for the OPs code, see a [live example](http://coliru.stacked-crooked.com/a/5af1d78f92469aef) using the following flags: `-Wall -Wextra -Wconversion -pedantic -fsanitize=undefined`. – Shafik Yaghmour May 02 '14 at 12:06
  • By the time I read the question, OP understood the problem in his question and edited the question. I answered only the edited part. You said **this is still undefined behavious**. I tried my [piece of code](http://coliru.stacked-crooked.com/a/bf2a456981ae73d8) and it doesn't exhibit a warning. Or may be I missed something you want to convey. – Mohit Jain May 02 '14 at 12:16
-1

Your code works as expected for me (gcc 4.6.3 on 12.04LTS). But it produces couple of warnings about shift count being greater than the width of type.

Compilation gives:

Test.c: In function ‘main’:

Test.c:5:5: warning: left shift count >= width of type [enabled by default]

Test.c:6:4: warning: left shift count >= width of type [enabled by default]

Output of run:

4 8

0 0

Good Luck!

Lallu Anthoor
  • 231
  • 1
  • 5