【问题标题】:Initializing objects with macros for integer constants使用整数常量的宏初始化对象
【发布时间】:2016-11-03 16:13:03
【问题描述】:

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

1 以下类似函数的宏扩展为整数常量 适用于初始化具有整数类型的对象 对应于 中定义的类型。每个宏名称 对应于 7.20.1.2 或 7.20.1.5 中的类似类型名称。

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

UINT64_C(0x123) => 0x123ULL

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

uint64_t x = 0x123; 

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

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

【问题讨论】:

  • 我认为引入这些宏只是为了解决语言缺陷,即 stdint.h 类型没有整数文字后缀。有点像 inttypes.h 中 printf 的格式说明符。

标签: c macros integer c11


【解决方案1】:

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 来说太大,第一种情况会产生一个更宽类型的具有指定值的常量,第二种情况会产生一个转换后的值到命名的类型。这些可能导致什么错误以及编译器是否会诊断问题可能取决于上下文。

【讨论】:

    【解决方案2】:

    使用 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]
    

    【讨论】:

    • 您收到警告是因为分配,而不是因为后缀。后缀从不沮丧。如果您printf("%u\n", 0x100000000U);,您会收到有关格式字符串错误(不是截断)的警告。
    猜你喜欢
    • 1970-01-01
    • 2013-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 2019-08-28
    相关资源
    最近更新 更多