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

时间:2018-09-24 16:42:50

标签: c types casting undefined-behavior sign

我被一个意外的整数提升所咬住,使我感到奇怪。 是否在显式强制转换之前进行升级是否在整个编译器中一致?

让我解释一下。具有签名的8位变量,例如

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

将一个未签名的16分配为uint16_t s16b = s8a + 1;,我希望将其提升为更大的整数0xFF81,然后再分配,这是一个普遍的事故,在MISRA C等文档中都可以使用。我希望uint16_t s16b = (uint16_t)s8a会立即失去其“符号”,然后零扩展到16位以得到s8a,但实际上却相反,因为它当强制转换并赋予0x0080时,符号扩展的 then 会失去其签名。

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

2 个答案:

答案 0 :(得分:4)

这与整数提升无关,但与类型转换有关。在您的情况下,该过程由C11 Standard - 6.3.1.3 Signed and unsigned integers (p2)进行了很好的定义:

  

..如果新类型是无符号的,则该值将通过重复转换   比最大值增加或减去一个以上   以新类型表示,直到值在新范围内   类型。

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

答案 1 :(得分:1)

给出初始化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