带括号的子表达式的类型提升规则是什么?

What is the type promotion rule for a parenthesized sub-expression?

假设一个整数表达式由多个无符号整数类型 uint16_tuint32_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 在线编译器中尝试此操作表明 a16b16 在乘法之前被提升为 uint32_t。这是C标准规定的吗?为什么不在括号内求值为 uint16_t

所有小于 int 的类型在乘法之前被提升为 int

所以如果你有一个 32 位 2 的补码 int 那么结果实际上是两个 int32_t 类型的乘积。

表达式中的圆括号对这种隐式类型转换或最终结果没有影响。

只要小于 int 的类型用于表达式,它首先被提升为 intunsigned 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?

没有。主要有两种可能:

  1. uint16_tunsigned int 类型相同。在这种情况下,在使用两个 uint16_t 操作数计算运算时不执行任何提升,结果的类型为 uint16_t.

  2. intuint16_t宽,因此可以表示uint16_t可以表示的所有值。在这种情况下,当二元运算符的两个操作数都具有类型 uint16_t 时,它们都被提升为 int(这肯定与 uint32_t 不同),并且运算结果具有输入 int.

原则上,C不排除在实践中你永远不会看到的第三种可能性:

  1. uint16_tunsigned int 不是同一类型,但大小相同。在这种情况下,您要么晋升到 unsigned int(在这种情况下不能与 uint32_t 相同),要么没有晋升。

在任何情况下都不允许符合标准的 C 实现将有问题的操作数提升为 uint32_t,具有两个 uint16_t 操作数的操作也不会产生 uint32_t 结果。