9

I'm a bit confused because I wanted to initialize a variable of type unsigned long whose size is 8 bytes on my system (on every modern system I suppose). When I want to assign 1 << 63 to the variable, I get a compiler warning however and the number is in fact 0. When I do 1 << 30 I get the expected result of 2 ^ 30 = 1073741824. Yet when I do 1 << 31, I get the result of 2 ^ 64 (I think; actually this shouldn't be possible) which prints 18446744071562067968.

Can anyone explain this behaviour to me?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
borchero
  • 5,562
  • 8
  • 46
  • 72
  • 5
    did you try `1UL << 63` – Sourav Ghosh Jul 31 '15 at 10:48
  • No, never seen this notation (I'm pretty new to C), thanks :) – borchero Jul 31 '15 at 10:49
  • 1
    @OliverBorchert You can suffix a number with `U` for `unsigned` and `L` for `long` to change the type of that literal. There are some other suffixes, look in a C book for more details. – fuz Jul 31 '15 at 10:54
  • similar http://stackoverflow.com/q/25838378/995714 – phuclv Jul 31 '15 at 11:15
  • Possible duplicate of [What does the C standard say about bitshifting more bits than the width of type?](https://stackoverflow.com/questions/11270492/what-does-the-c-standard-say-about-bitshifting-more-bits-than-the-width-of-type) – phuclv Sep 08 '18 at 05:56

4 Answers4

15

1 << 63 will be computed in int arithmetic, and your int is probably 32 bit.

Remedy this by promoting the left argument: 1ULL << 63 will do it.

ULL means the expression will be at least 64 bits.

vitiral
  • 8,446
  • 8
  • 29
  • 43
P45 Imminent
  • 8,319
  • 4
  • 35
  • 78
  • Yeah ok, thank you, I'll accept the answer as soon as it is possible – borchero Jul 31 '15 at 10:50
  • actually `UL` is not 64 bits long on 32-bit architectures, `ULL` is. – dwalter Jul 31 '15 at 11:07
  • 1
    Nitpicking, but unless it's been changed in a newer standard than the one I have, unsigned long isn't guaranteed to be more than 32 bits, since ULONG_MAX isn't guaranteed to be more than 4294967295. – Thomas Padron-McCarthy Jul 31 '15 at 11:09
  • wrong. `long` is just guaranteed to be at least 32 bits, and it's still 32 bits on 64-bit windows. Only `long long` are at least 64 bits, and you must use `ULL` for that – phuclv Jul 31 '15 at 11:26
  • 4
    This answer is misleading. It says "by promoting one of the arguments", which seems to suggest that it is sufficient to promote any of the two arguments. In reality shift operators are *special* in the sense that changing the type of the right operand does not lead to promotion of the left operand. In this case it is important to change the type of the left operand specifically, not "one of the arguments" as this answer misleadingly suggests. – AnT stands with Russia Dec 18 '17 at 16:54
3

The expression 1 << 63 has type int. The range of an int is -231 … 231 - 1 on most systems, 263 is too large for that. Try either (unsigned long)1 << 63 or 1UL << 63 to shift a value of type unsigned long left by 63 places.

fuz
  • 88,405
  • 25
  • 200
  • 352
3

The 1 here, is called an integer constant. By the norms specified in the standard, C11, chapter §6.4.4.1 the syntax for the same is

integer-constant:
     decimal-constant integer-suffixopt
     octal-constant integer-suffixopt
      hexadecimal-constant integer-suffixopt

and regarding the Semantics,

The type of an integer constant is the first of the corresponding list in which its value can be represented.

and the table says, if there is no suffix, and the value is representable in the int range it should be considered as int. So, 1 here, is considered an int, which is of generally 4 bytes, or 32 bits, also same in your case.

To explicitly specify the 1 as unsigned long (64) bit, we can use the suffix, like

1UL << 63

should solve your issue.

Please note: unsigned long is not guaranteed to be of 64 bits. unsigned long long is guaranteed to have at least 64 bits. However, as long as you're using the platform where unsigned long is of 64 bits , you should be fine

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • `unsigned long long` is not guaranteed to be 64 bits either, it could be 128 bits or something like that. – fuz Jul 31 '15 at 11:23
  • @FUZxxl It is _at least_ 64 bits guranteed. I can shift 128 bit variable(s) to 64 bits places without any issues, in other case. :-) – Sourav Ghosh Jul 31 '15 at 11:30
  • I just wanted to point out that `unsigned long long` may not be exactly 64 bits long (it's merely *at least* 64 bits long), your answer indicates the opposite. – fuz Jul 31 '15 at 11:33
  • @FUZxxl Thanks sir. :-) – Sourav Ghosh Jul 31 '15 at 13:51
2

I recommend that you use 1ULL since this will give you a 64-bit unsigned integer on 32 and 64 bit architecture. On 32 Bit architecture unsigned long (and therefor UL) is only 32 bit long and will not solve the problem.

1ULL << 63
dwalter
  • 7,258
  • 1
  • 32
  • 34
  • 2
    Keep in mind that `unsigned long long` is a type that is not available on C89 platforms. – fuz Jul 31 '15 at 11:23