你的第二个例子是不是有效的C99,看起来像C++。也许你想要的是演员,即(int32_t)(a/UINT64_C(1000000000))
?
有a/UINT64_C(1000000000)
和a/1000000000
之间的差异?不,他们会以相同的操作结束。但我不认为这真的是你的问题。
我认为你的问题归结到会出现什么整数文字的类型“10亿”是什么?它会是一个int32_t或int64_t? C99中的答案来自§6.4.4.1第5段:
整数常量的类型是其中可以表示其值的对应列表的第一个。
对于无后缀十进制常量,该列表是int
,long int
,long long int
。因此,第一个文字几乎肯定会是一个int
(取决于一个int
的规模,这将可能是32位,并为此大到足以容纳一个十亿)。带有UINT64_C宏的第二个字面值可能是unsigned long
或unsigned long long
,具体取决于平台。它将是与uint64_t
相对应的任何类型。
所以类型的常量是不一样的。第一个将被签名,而第二个未签名。第二个很可能会有更多的“长”,这取决于编译器的基本int类型的大小。
在您的例子,它使没有区别的文字有不同的类型,因为/
运营商将需要促进字面来的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
为了计算c
,编译器将需要促进a
到uint64_t
并执行64位乘法。但是要计算b
,编译器将使用32位乘法,因为这两个值都是32位。
在最后一个例子,我们可以使用强制的,而不是宏观:
uint64_t c = (uint_least64_t)(1000000000) * a;
这将迫使也是乘法至少为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
另一种可能性是预处理器表达式。一个强制转换不是用于#if
指令表达式的合法语法。但是UINTxx_C()
宏是。
由于宏使用粘贴到文字上的后缀,并且没有后缀,所以可能会发现UINT16_C(x)和UINT32_C(x)是相同的。这给出了结果(uint_least16_t)(65537) != UINT16_C(65537)
。不是人们所期望的。事实上,我很难看到它如何符合C99§7.18.4.1:
宏UINTN_C(值)应扩展为与uint_leastN_t类型对应的整型常量表达式。
这是不好的编辑您的问题,以便它使现有答案中的问题无效。 –
另外,我很好奇为什么你问的是旧的C99标准,而不是“通用C”或C11标准。当然,''和''设施不是C90的一部分,但现在C99也很老旧。 –
@JonathanLeffler我修正了编辑问题。我问的是C99,因为它是ANSI C之后最广泛支持的标准,并且是我正在使用的标准。如果所有的编译器都支持C11,那么世界会更好,但事实并非如此...... – user3368561