标准 C 中是否需要文字后缀?

use*_*561 1 c c99

有一个问题已经回答了变量声明的特殊情况,但是其他文字常量的使用呢?

例如:

uint64_t a;
...
int32_t b = a / 1000000000;
Run Code Online (Sandbox Code Playgroud)

在任何标准 C 编译器中,最后一段代码是否等同于下一段代码?

uint64_t a;
...
int32_t b = (int32_t)(a / UINT64_C(1000000000));
Run Code Online (Sandbox Code Playgroud)

换句话说,是否需要 xINTn_C 宏(假设我们在隐式错误的情况下使用显式转换)?

编辑

当编译器读取 时1000000000,是否允许将其存储为int内部表示(删除所有溢出位),或者它必须以尽可能高的精度(long long)存储它,直到它解析整个表达式类型?它是实现定义的行为还是标准规定的?

Tre*_*ntP 5

你的第二个例子不是有效的 C99,看起来像 C++。也许你想要的是演员表,即(int32_t)(a / UINT64_C(1000000000))

有没有之间的差异a / UINT64_C(1000000000)a / 1000000000?不,他们最终会进行相同的操作。但我不认为这真的是你的问题。

我认为您的问题归结为整数文字“1000000000”的类型是什么?它是 int32_t 还是 int64_t?C99 中的答案来自 §6.4.4.1 第 5 段:

整数常量的类型是其值可以在其中表示的相应列表中的第一个。

对于没有后缀的十进制常量,列表为int, long int, long long int。所以第一个文字几乎肯定是 an int(取决于an的大小int,它可能是 32 位,因此大到足以容纳 10 亿)。带有 UINT64_C 宏的第二个文字可能是 aunsigned longunsigned long long,具体取决于平台。它将是对应于的任何类型uint64_t

所以常量的类型是不一样的。第一个将被签名,而第二个是未签名的。第二个很可能有更多的“long”,这取决于基本 int 类型的编译器大小。

在您的示例中,文字具有不同的类型没有区别,因为/运算符需要将文字提升为 of 的类型a(因为a在任何情况下都将与文字具有相同或更高的等级)。这就是为什么我不认为这真的是你的问题。

有关为什么UINT64_C()重要的示例,请考虑一个表达式,如果将文字提升为更大的类型,则结果会发生变化。即,溢出将发生在文字的本机类型中。

int32_t a = 10;
uint64_t b = 1000000000 * a;  // overflows 32-bits
uint64_t c = UINT64_C(1000000000) * a; // constant is 64-bit, no overflow
Run Code Online (Sandbox Code Playgroud)

为了计算c,编译器将需要推动auint64_t并执行64位乘法。但是为了计算b编译器将使用 32 位乘法,因为两个值都是 32 位。

在最后一个示例中,可以使用强制转换而不是宏:

uint64_t c = (uint_least64_t)(1000000000) * a;
Run Code Online (Sandbox Code Playgroud)

这也将迫使乘法至少为 64 位。

为什么你会使用宏而不是转换文字?一种可能性是因为十进制文字是有符号的。假设您想要一个不能表示为有符号值的常量?例如:

uint64_t x = (uint64_t)9888777666555444333;    // warning, literal is too large
uint64_t y = UINT64_C(9888777666555444333);    // works
uint64_t z = (uint64_t)(9888777666555444333U); // also works
Run Code Online (Sandbox Code Playgroud)

另一种可能性是预处理器表达式。强制转换不是用于#if指令表达式的合法语法。但是UINTxx_C()宏是。

由于宏使用粘贴到文字上的后缀并且没有短后缀,因此您可能会发现 UINT16_C(x) 和 UINT32_C(x) 是相同的。这给出的结果是(uint_least16_t)(65537) != UINT16_C(65537)。不是人们所期望的。事实上,我很难看出这如何符合 C99 §7.18.4.1:

宏 UINTN_C(value) 应扩展为对应于类型 uint_leastN_t 的整数常量表达式。