问题
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 7.20.4 introduces Macro integer constants with:
1 The following function-like macros expand to integer constants suitable for initializing objects that have integer types corresponding to types defined in <stdint.h>. Each macro name corresponds to a similar type name in 7.20.1.2 or 7.20.1.5.
I don't quite understand this paragraph. The macros basically slap the appropriate suffix onto an unsuffixed number as in:
UINT64_C(0x123) => 0x123ULL
But if I wanted to initializes an uint64_t, I would just do:
uint64_t x = 0x123;
and I wouldn't bother with the suffix at all.
Why would I need these macros in initializations?
回答1:
this UINT64_C(0x123)
macro creates an immediate unsigned long long number so it can be used in variable argument functions for instance or intermediate computations without the need for casting into the uint64_t
type, where it is important that this particular data type is used.
Example:
printf("%llu\n",UINT64_C(0x123));
is correct
printf("%llu\n",0x123);
is incorrect and is UB because data size isn't correct, and printf
cannot know that.
when you do uint64_t x = 0x123;
, there's an assignment and an implicit cast, so no need to do this (and printf("%llu\n",x);
is correct)
Another usage is in intermediate computations, as illustrated below:
uint32_t a = 0xFFFFFFFF;
uint64_t x = a + UINT64_C(0xFFFFFFFF);
won't overflow whereas
x = a + 0xFFFFFFFF;
will overflow because intermediate result is stored in a uint32_t
As a conclusion, the main functional difference between UINT64_C(SOME_CONSTANT)
and (uint64_t)SOME_CONSTANT
is that if the value overflows, you'll get a warning in the first case for sure, and a "conversion" in the other case (and maybe a warning but that depends on the compiler).
回答2:
With u64 you tell that you want 64-bit integer. Some platforms provide it by defining unsigned long long
, others by unsigned long
. If your values are to interoperate with functions that need this info (e.g. printf and pals), you should deal with this indirection in order to have flexible code.
In your example (uint64_t ex = 0x123;
) type has this information, no need to explicitly call the macro. But I assume you need all the 64-bit, if it exceeds int
values, you should have the UL
/ ULL
postfices. Example:
unsigned ex = 0x100000000U;
// warning: large integer implicitly truncated to unsigned type [-Woverflow]
来源:https://stackoverflow.com/questions/40406394/initializing-objects-with-macros-for-integer-constants