标准C是否需要文字后缀? [英] Are literal suffixes needed in standard C?

查看:97
本文介绍了标准C是否需要文字后缀?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已经有一个问题可以回答变量声明的特殊情况,但是其他文字常量用法又如何呢?

There is a question already answering the particular case of variable declaration, but what about other literal constant uses?

例如:

uint64_t a;
...
int32_t b = a / 1000000000;

最后一段代码是否等效于任何标准C编译器中的下一个代码?

Is last piece of code equivalent to next one in any standard C compiler?

uint64_t a;
...
int32_t b = (int32_t)(a / UINT64_C(1000000000));

换句话说,根本是否需要xINTn_C宏(假设在隐式情况下使用显式强制转换

In other words, are xINTn_C macros needed at all (supposing we are using explicit casting in cases where implicit one is wrong)?

EDIT

当编译器读取<$ c $时c> 1000000000 ,是否允许以内部表示形式将其存储为 int (丢弃所有溢出位),或者必须将其存储在尽可能高的位置精度(很长很长),直到可以解析整个表达式类型?是实现定义的行为还是由标准强制执行?

When compiler reads 1000000000, is it allowed to store it as int in an internal representation (dropping all overflowing bits) or it must store it at highest possible precision (long long) until it resolves whole expression type? Is it an implementation-defined behavior or it is mandated by the standard?

推荐答案

第二个示例不是有效的C99,看起来像C ++。也许想要的是强制转换,即(int32_t)(a / UINT64_C(1000000000))

Your second example isn't valid C99 and looks like C++. Perhaps want you want is a cast, i.e. (int32_t)(a / UINT64_C(1000000000))?

a / UINT64_C(1000000000) a / 1000000000 之间有区别吗?不,他们最终将进行相同的操作。但是我不认为这真的是您的问题。

Is there a difference between a / UINT64_C(1000000000) and a / 1000000000? No, they'll end up with the same operation. But I don't think that's really your question.

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

I think your question boils down to what will the type of the integer literal "1000000000" be? Will it be an int32_t or an int64_t? The answer in C99 comes from §6.4.4.1 paragraph 5:


整数常量的类型是相应列表的第一个,其中

The type of an integer constant is the first of the corresponding list in which its value can be represented.

对于不带后缀的十进制常量,列表为 int long int long long int 。因此,第一个文字几乎可以肯定是 int (取决于 int 的大小,该大小可能为32 -位,因此足以容纳十亿个位)。根据平台的不同,带有UINT64_C宏的第二个文字可能是 unsigned long unsigned long long ,具体取决于平台。它将是与 uint64_t 相对应的任何类型。

For decimal constants with no suffix, the list is int, long int, long long int. So the first literal will almost certainly be an int (depend on the size of an int, which will likely be 32-bits and therefor large enough to hold one billion). The second literal with the UINT64_C macro will likely be either a unsigned long or unsigned long long, depending on the platform. It will be whatever type corresponds to uint64_t.

因此常量的类型并不相同。第一个将被签名,而第二个将被未签名。第二个很有可能具有更多的 longs,具体取决于编译器的基本int类型的大小。

So the types of the constants are not the same. The first will be signed while the second is unsigned. And the second will most likely have more "longs", depending on the compiler's sizes of the basic int types.

在您的示例中,这些文字具有相同的含义不同的类型,因为 / 运算符将需要将文字提升为 a 的类型(因为 a 的排名都将等于或大于文字的排名)。这就是为什么我认为这不是您真正的问题。

In your example, it makes no difference that the literals have different types because the / operator will need to promote the literal to the type of a (because a will be of equal or greater rank than the literal in any case). Which is why I didn't think that was really your question.

举例说明为什么 UINT64_C()会很重要,请考虑如果将文字提升为更大的类型,则结果会发生变化的表达式。也就是说,文字的本机类型中会发生溢出。

For an example of why UINT64_C() would matter, consider an expression where the result changes if the literals are promoted to a larger type. I.e., overflow will occur in the literals' native types.

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

要计算 c ,编译器将需要将 a 升级为 uint64_t 并执行64位乘法。但是要计算 b ,编译器将使用32位乘法,因为两个值都是32位。

To compute c, the compiler will need to promote a to uint64_t and perform a 64-bit multiplication. But to compute b the compiler will use 32-bit multiplication since both values are 32-bits.

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

In the last example, one could use a cast instead of the macro:

uint64_t c = (uint_least64_t)(1000000000) * a;

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

That would also force the multiplication to be at least 64 bits.

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

Why would you ever use the macro instead of casting a literal? One possibility is because decimal literals are signed. Suppose you want a constant that isn't representable as a signed value? For example:

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

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

Another possibility is for preprocessor expressions. A cast isn't legal syntax for use in the expression of a #if directive. But the UINTxx_C() macros are.

由于宏使用粘贴到文字上的后缀,因此没有后缀一小段时间,您可能会发现UINT16_C(x)和UINT32_C(x)是相同的。结果为(uint_least16_t)(65537)!= UINT16_C(65537)。不是人们所期望的。实际上,我很难理解它如何符合C99§7.18.4.1:

Since the macros use suffixes pasted onto literals and there is no suffix for a short, one will likely find that UINT16_C(x) and UINT32_C(x) are identical. This gives the result that (uint_least16_t)(65537) != UINT16_C(65537). Not what one might expect. In fact, I have a hard time seeing how this complies with C99 §7.18.4.1:


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

The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.

这篇关于标准C是否需要文字后缀?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆