整数提升如何在 C Cast 上工作?

How does integer promotion work on C Cast?

我被意外的整数提升所困扰,这让我感到奇怪。 是否在显式转换之前进行提升是否在编译器之间保持一致?

让我解释一下。有一个带符号的 8 位变量,例如

int8_t s8a = -128; //<-- 0x80

将无符号 16 分配为 uint16_t s16b = s8a + 1; 我希望提升为更大的整数 0xFF81 然后分配,这是一个常见的错误,并且在 MISRA C 等文档中考虑过。但是显式转换以 uint16_t s16b = (uint16_t)s8a 之类的方式转换为无符号类型我希望 s8a 立即丢失其 "signedness" 然后零扩展到 16 位以给出 0x0080 但实际上相反发生了,因为它得到符号扩展 然后 在铸造和赋值时失去其符号性 0xFF80.

这是标准行为还是 C 的另一个未定义行为?

这与整数提升无关,而是与类型转换有关。在您的情况下,该过程由 C11 Standard - 6.3.1.3 Signed and unsigned integers (p2):

明确定义

.. if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

所以这里 0xFF80 = 0xFFFF + (-128) + 1,因为 0xFFFFuint16_t 中可以表示的最大值。

给定初始化int8_t s8a = -128;:

  1. 在初始化的情况下uint16_t s16b = s8a + 1;
    1. 在表达式s8a + 1中,s8a(int8_t)-128)中的值被提升为(int)-128并加上(int)1得到(int)-127.
    2. 在初始化uint16_t s16b = (int)-127;时,将(int)-127转换为(uint16_t)0xff81存入s16b
  2. 在初始化的情况下uint16_t s16b = (uint16_t)s8a + 1;
    1. 在表达式(uint16_t)s8a中,s8a((int8_t)-128)中的值被转换为(uint16_t)0xff80.
    2. 在表达式 (uint16_t)0xff80 + 1 中:
      • 如果INT_MAX >= 65535,则(uint16_t)0xff80转换为(int)0xff80并加上(int)1得到(int)0xff81.
      • 如果INT_MAX < 65535,则1转换为(uint16_t)1加上(uint16_t)0xff80得到(uint16_t)0xff81.
    3. 在初始化uint16_t s16b = (int)0xff81;(当INT_MAX >= 65535),或初始化uint16_t s16b = (uint16_t)0xff81;(当INT_MAX < 65535):
      • 如果INT_MAX >= 65535,则(int)0xff81转换为(uint16_t)0xff81,存入s16b
      • 如果INT_MAX < 65535,则(uint16_t)0xff81存储在s16b

在这两种情况下,s16b 都被初始化为值 (uint16_t)0xff81