带括号的子表达式的类型提升规则是什么?
What is the type promotion rule for a parenthesized sub-expression?
假设一个整数表达式由多个无符号整数类型 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%08x\n", d32);
return 0;
}
在 ideone 在线编译器中尝试此操作表明 a16
和 b16
在乘法之前被提升为 uint32_t
。这是C标准规定的吗?为什么不在括号内求值为 uint16_t
?
所有小于 int
的类型在乘法之前被提升为 int
。
所以如果你有一个 32 位 2 的补码 int
那么结果实际上是两个 int32_t
类型的乘积。
表达式中的圆括号对这种隐式类型转换或最终结果没有影响。
只要小于 int
的类型用于表达式,它首先被提升为 int
或 unsigned int
,而不管表达式的上下文如何。
这在 C standard 的第 6.3.1.1p2 节中有详细说明:
The following may be used in an expression wherever an int
or
unsigned int
may be used
- An object or expression with an integer type (other than
int
or unsigned int
) whose integer conversion rank is less
than or equal to the rank of int
and unsigned int
.
- A bit-field of type
_Bool
, int
, signed int
,or unsigned int
.
If an int
can represent all values of the original type (as
restricted by the width, for a bit-field), the value is
converted to an int
; otherwise, it is converted to an
unsigned int
. These are called the integer promotions. All
other types are unchanged by the integer promotions
因此,在您的情况下,假设 int
大于 uint16_t
.
注意这是整数提升,与通常的算术转换不同。后者规定了在应用运算符之前如何将两个不同类型的操作数转换为通用类型。
Assume an integer expression comprised of multiple unsigned integral
types uint16_t and uint32_t. The expression contains a parenthesized
sub-expression, within which all elements are of type uint16_t.
Should the elements inside the parenthesized sub-expression be
promoted to uint32_t prior to evaluating the sub-expression?
没有。主要有两种可能:
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
结果。
假设一个整数表达式由多个无符号整数类型 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%08x\n", d32);
return 0;
}
在 ideone 在线编译器中尝试此操作表明 a16
和 b16
在乘法之前被提升为 uint32_t
。这是C标准规定的吗?为什么不在括号内求值为 uint16_t
?
所有小于 int
的类型在乘法之前被提升为 int
。
所以如果你有一个 32 位 2 的补码 int
那么结果实际上是两个 int32_t
类型的乘积。
表达式中的圆括号对这种隐式类型转换或最终结果没有影响。
只要小于 int
的类型用于表达式,它首先被提升为 int
或 unsigned int
,而不管表达式的上下文如何。
这在 C standard 的第 6.3.1.1p2 节中有详细说明:
The following may be used in an expression wherever an
int
orunsigned int
may be used
- An object or expression with an integer type (other than
int
orunsigned int
) whose integer conversion rank is less than or equal to the rank ofint
andunsigned int
.- A bit-field of type
_Bool
,int
,signed int
,orunsigned int
.If an
int
can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to anint
; otherwise, it is converted to anunsigned int
. These are called the integer promotions. All other types are unchanged by the integer promotions
因此,在您的情况下,假设 int
大于 uint16_t
.
注意这是整数提升,与通常的算术转换不同。后者规定了在应用运算符之前如何将两个不同类型的操作数转换为通用类型。
Assume an integer expression comprised of multiple unsigned integral types uint16_t and uint32_t. The expression contains a parenthesized sub-expression, within which all elements are of type uint16_t.
Should the elements inside the parenthesized sub-expression be promoted to uint32_t prior to evaluating the sub-expression?
没有。主要有两种可能:
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
结果。