使用整数常量的宏初始化对象

Initializing objects with macros for integer constants

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 7.20.4 引入了 宏整数常量 和:

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.

这段我不太明白。 宏基本上将适当的后缀添加到无后缀的数字上,如:

UINT64_C(0x123) => 0x123ULL

但是如果我想初始化一个 uint64_t,我会这样做:

uint64_t x = 0x123; 

而且我根本不会为后缀烦恼。

为什么我在初始化时需要这些宏?

UINT64_C(0x123) 宏创建一个立即数 unsigned long long 数字,因此它可以用于变量参数函数中,例如实例或中间计算,而无需转换为 uint64_t 类型,其中使用这种特定的数据类型很重要。

示例:

printf("%llu\n",UINT64_C(0x123));

正确

printf("%llu\n",0x123);

不正确并且是未定义的行为,因为数据大小不正确,而 printf 通常不知道这一点。

当你使用uint64_t x = 0x123;时,有一个赋值和一个隐式转换,所以不需要这样做(而且printf("%llu\n",x);是正确的)。

另一种用法是在中间计算中,如下图所示:

uint32_t a = 0xFFFFFFFF;
uint64_t x = a + UINT64_C(0xFFFFFFFF);

将产生完整的 64 位和,而

x = a + 0xFFFFFFFF;

将在 32 位内换行,因为中间结果使用 uint32_t 类型。

UINT64_C(SOME_CONSTANT)(uint64_t) SOME_CONSTANT的区别在于,如果UINT64_C的值太大,第一种情况会产生一个更宽类型的具有指定值的常量,第二个将生成一个转换为命名类型的值。这些会导致什么错误以及编译器是否会诊断问题可能取决于上下文。

使用 u64 表示您需要 64 位整数。一些平台通过定义 unsigned long long 来提供它,其他平台通过 unsigned long 来提供它。如果您的值要与需要此信息的函数进行互操作(例如 printf 和 pals),您应该处理此间接以获得灵活的代码。 在您的示例中 (uint64_t ex = 0x123;) 类型具有此信息,无需显式调用宏。但我假设你需要所有 64 位,如果它超过 int 值,你应该有 UL / ULL 后缀。示例:

unsigned ex = 0x100000000U;
// warning: large integer implicitly truncated to unsigned type [-Woverflow]