0

Here's my code:

#include <stdio.h>

int main(int argc, char *argv[]) {

    unsigned long int x = 0;

    // trying to make x = 2,147,483,648
    x = 1 << 31;

    printf("%lu", x);
}

It's returning that x = 18446744071562067968. I read that unsigned long int should go up to 4,294,967,296, so why can't I use 1 << 32 to set x equal to 2,147,483,648?

Austin
  • 6,921
  • 12
  • 73
  • 138
  • Wherever this was written: it is wrong! http://port70.net/~nsz/c/c11/n1570.html#5.2.4.2.1 And get the maths right. Hint: the max. value cannot be even. – too honest for this site Jan 31 '16 at 20:34
  • Hu? It says maximum value for an object of type unsigned long int ULONG_MAX 4294967295 // 2^32 - 1 – Austin Jan 31 '16 at 20:35
  • On popular request, I try to help you a bit. The last sentence of paragraph 1 in the posted link to the C standard states "Their implementation-defined values shall be **equal or greater** in magnitude (absolute value) to those shown, with the same sign.". Hope the emphasis helps. Also note that you shift by `31` in the code, but by `32` in the text. So much for "off by one count"; that just doubles the value and results in undefined behaviour for windows `unsigned long`. For POSIX, it is well correct, btw. as that has 64 bits. – too honest for this site Jan 31 '16 at 21:18
  • [Type of integer literals not int by default?](https://stackoverflow.com/q/8108642/995714), [What is the default type of integral literals represented in hex or octal in C++?](https://stackoverflow.com/q/38782709/995714) – phuclv Oct 16 '18 at 10:28
  • Possible duplicate of [bit shifting with unsigned long type produces wrong results](https://stackoverflow.com/questions/31744305/bit-shifting-with-unsigned-long-type-produces-wrong-results) – phuclv Oct 16 '18 at 10:28

1 Answers1

3

1 << 31 causes undefined behaviour, if your system has 32-bit ints. The literal 1 is a signed int.

You need to do an unsigned shift instead of a signed shift:

x = 1UL << 31;

I added L so that the code is still correct even on a 16-bit system, and it doesn't hurt to do so.


Informally, shifting a 1 into the sign bit is undefined. The formal text can be found in section 6.5.7/4 of the C11 standard:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] 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.


Your other question, "why can't I use 1 << 32" is covered by that same quote. What about 1UL << 32 ? If your system has 32-bit unsigned long then this would also be undefined according to 6.5.7/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

But it would work if your system had 64-bit unsigned long. To avoid having your code break when compiled on a different system (this goal is known as code portability) you could write (uint64_t)1 << 32 (or 1ULL << 32) which is guaranteed to work.

M.M
  • 138,810
  • 21
  • 208
  • 365