假设一个由多个无符号整数类型uint16_t
和uint32_t
组成的整数表达式。表达式包含一个带括号的子表达式,其中所有元素的类型都是uint16_t
。
在评估子表达式之前,是否应将带括号的子表达式中的元素提升为uint32_t
?
例如:
#include <stdint.h>
#include <stdio.h>
int main(void)
{
uint16_t a16 = 0x2000;
uint16_t b16 = 0x3000;
uint32_t c32 = 0x00000001;
uint32_t d32;
// Should (a16 * b16) be evaluated to 0x06000000, or to 0x0000?
// Should d32 be evaluated to 0x06000001, or to 0x00000001?
d32 = c32 + (a16 * b16);
printf("d32=0x%08xn", d32);
return 0;
}
在ideone在线编译器中尝试此操作表明a16
和b16
在乘法之前被提升为uint32_t
。这是C标准强制要求的吗?为什么不在括号内计算为uint16_t
?
在表达式中使用小于int
的类型时,无论表达式的上下文如何,它都会首先升级为int
或unsigned int
。
这在C标准的6.3.1.1p2节中有详细说明:
以下内容可用于
int
或unsigned int
可用于
- 具有整数类型(
int
或unsigned int
除外(的对象或表达式,其整数转换秩小于大于或等于CCD_ 16和CCD_- 类型为
_Bool
、int
、signed int
或unsigned int
的位字段如果
int
可以表示原始类型的所有值(如受宽度限制,对于位字段(,值为转换为CCD_ 23;否则,它将转换为unsigned int
。这些被称为整数促销全部其他类型不受整数促销的影响
因此,在您的情况下,假设int
大于uint16_t
,则a16
和b16
在应用于任何运算符之前都将升级为int
。
请注意,这是整数提升,与常用算术转换不同。后者规定了在应用运算符之前如何将不同类型的两个操作数转换为公共类型。
所有小于int
的类型在相乘之前都会升级为int
。
因此,如果你有一个32位2的补码int
,那么结果实际上是两个int32_t
类型的乘积。
表达式中的括号对这种隐式类型转换或最终结果都没有影响。
假设一个由多个无符号整数组成的整数表达式类型uint16_t和uint32_t。表达式包含带括号的子表达式,其中所有元素都是uint16_t类型。
带括号的子表达式中的元素应该是在评估子表达式之前提升为uint32_t?
否。主要有两种可能性:
-
uint16_t
与unsigned int
属于同一类型。在这种情况下,在评估具有两个uint16_t
操作数的操作时不执行提升,并且结果的类型为uint16_t
。 -
int
比uint16_t
宽,因此可以表示由uint16_t
表示的所有值。在这种情况下,当二进制运算符的两个操作数都具有类型uint16_t
时,两者都被提升为int
(这肯定与uint32_t
不同(,并且运算的结果具有类型int
。
原则上,C不排除在实践中永远不会看到的第三种可能性:
uint16_t
与unsigned int
的类型不同,但大小相同。在这种情况下,您将升级到unsigned int
(在这种情况中不能与uint32_t
相同(或不升级
在符合C实现的任何情况下,有问题的操作数都不会提升为uint32_t
,具有两个uint16_t
操作数的运算也不会产生uint32_t
结果。