23

What I'm trying to do is to define a constant equal to 2^30 (I may change it to something like 2^34, so I prefer to have a room larger than 32 bits for it).

Why the following minimal(?) example doesn't compile?

#include <stdint.h>
// test.cpp:4:33: error: expected primary-expression before numeric constant
// test.cpp:4:33: error: expected ')' before numeric constant
const uint64_t test = (uint64_t 1) << 30;
//const uint64_t test1 = (uint64_t(1)) << 30;// this one magically compiles! why?

int main() { return 0; }
fiktor
  • 1,303
  • 2
  • 11
  • 22

3 Answers3

45

You can use the macro:

UINT64_C

to define a 64bit unsigned integer literal, the cstdint header provides macros for defining integer literals of specific sizes, we see that in section 18.4.1 Header synopsis:

The header also defines numerous macros of the form:

and includes:

plus function macros of the form:

[U]INT{8 16 32 64 MAX}_C

We have to go back to the C99 draft standard to find how they work, section 7.18.4.1 Macros for minimum-width integer constants which says:

[...]if uint_least64_t is a name for the type unsigned long long int, then UINT64_C(0x123) might expand to the integer constant 0x123ULL.

as the proper way of defining a 64bit integer constant expression. This is unfortunately not document on cpprefernce but cplusplus.com does document this feature for of the cstdint header as well as the posix reference for stdint.h.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    while not as directly applicable to the OP as the accepted answer, this answer is more generally useful, and should be the accepted answer for that reason. – Todd Freed Dec 30 '15 at 21:49
  • 2
    I would also include this link for reference : http://pubs.opengroup.org/onlinepubs/009695399/basedefs/stdint.h.html – Todd Freed Dec 30 '15 at 21:50
  • 1
    @ToddFreed ok, I will take a look at look at that reference. I have received a few upvotes for this recently and I am wondering if this has been linked from some outside site. – Shafik Yaghmour Dec 31 '15 at 01:09
16

The syntax you are looking for is:

const uint64_t test = 1ULL << 30;

The post-fix ULL is used for unsigned integer literals that are at least 64-bits wide.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Good to know this neat short notation. I would accept your answer too, if I could accept two answers. – fiktor Mar 12 '14 at 20:46
  • 3
    @fiktor This isn't a "short notation", this is *the* notation for writing numeric literals of a specified size. Using the casting method will end up being optimized to this on the first compiler pass (for any remotely decent compiler). – Zac Howland Mar 12 '14 at 22:30
  • 16
    This is not correct. If you are using uint64_t to define your integer type, you should use the corresponding literal notation, UINT64_C(arg). The "ULL" suffix corresponds exactly to "unsigned long long", while uint64_t might not, depending on the platform. This kind of platform independence is the only reason you would use uint64_t in the first place. – Todd Freed Dec 30 '15 at 21:46
  • 1
    @ToddFreed You realize that `UINT64_C` is a macro that expands to `value##ULL`, right? In other words, it does exactly the same thing I posted here. Claiming it is "incorrect" is factually wrong. – Zac Howland Jan 05 '16 at 18:05
  • 10
    On a platform where uint64_t == unsigned long long, UINT64_C will expand to ULL. On a platform where uint64_t == unsigned long, UINT64_C will expand to UL. Please read stdint.h. – Todd Freed Jan 05 '16 at 18:10
  • 1
    @ToddFreed stdint.h is going to be implementation specific, but every implementation I have installed currently has the same definition. So, if you want to be VERY specific, you could say that "on some off the wall platform, this might give you a warning as it is down-casting a larger integer to a smaller one", but to say it is "not correct" is inaccurate. It is actually what `stdint.h` does, in most cases. – Zac Howland Jan 05 '16 at 18:20
  • 3
    If you only care about platforms where uint64_t == unsigned long long, then your solution works fine. But then, why not use unsigned long long as your data type in the first place? Your initial statement which I was contesting is still wrong, "ULL is for unsigned 64-bit integers". A true statement would be, ULL is for unsigned long long integers. – Todd Freed Jan 05 '16 at 18:53
  • 1
    `long long int` is required, by the standard, to be *at least* 64-bits. So, if your complaint is that I didn't specify that, I think you are nit-picking and going well beyond what this question was asking almost 2 years ago. Additionally, your assertion that the only reason to use the `(u)int(n)_t` types is for platform independence is completely bogus. – Zac Howland Jan 05 '16 at 19:18
  • SO to if you want to be safe you'd use the macro like `const uint64_t test = UINT64_C(1) << 30;` ??? ... and this would make it platform independent??? – CpILL Sep 07 '17 at 18:21
6

(uint64_t 1) is not valid syntax. When casting, you can either use uint64_t(1) or (uint64_t) 1. The commented out example works because it follows the proper syntax for casting, as would:

const uint64_t test = ((uint64_t)1) << 30;

Edit: While this directly answers the question, see the answer by Shafik Yaghmour on how to properly define an integral constant with specific size.

clcto
  • 9,530
  • 20
  • 42
  • Yes, you are right. For some reason I forgot the brackets around the type, and they are indeed required for c-like cast notation. – fiktor Mar 12 '14 at 20:43
  • I usually just use sized literal suffixes `auto value = 1ui64 << 30;` (though sadly it appears that only MSVC supports typed suffixes whereas clang, gcc, and Intel compilers only support ULL after trying on Godbolt - oh well) – Dwayne Robinson Jan 11 '19 at 03:54