【问题标题】:Do integer promotions always happen when evaluating an expression? [duplicate]评估表达式时是否总是发生整数提升? [复制]
【发布时间】:2012-10-09 20:32:08
【问题描述】:

可能重复:
C integer overflow behaviour when assigning to larger-width integers

我在谷歌搜索中没有找到明确的答案。假设你有两个表达式:

int16_t a16 = 100;
int16_t b16 = 2000;
int16_t result16 = (a16 * b16) / a16;

int8_t a8 = 100;
int8_t b8 = 20;
int8_t result8 = (a8* b8) / a8;

在评估表达式 (a16 * b16) / a16(a8 * b8) / a8 时,它们总是在评估期间提升为 int,然后在分配,还是这个整数提升完全是可选的?是否总是在评估整数表达式时进行整数提升,还是只是允许?

如果它总是完成,那么我可以预期这两个操作不会溢出(假设 int 是 32 位)。如果只允许完成(而不是必需),则操作可能会溢出。我想更好地了解这种行为。

【问题讨论】:

    标签: c integer-promotion


    【解决方案1】:
    int16_t result16 = (a16 * b16) / a16;
    int8_t result8 = (a8* b8) / a8;
    

    这些声明与:

    int16_t result16 = (int16_t) ((int) a16 * (int) b16) / (int) a16);
    int8_t result8 = (int8_t) ((int) a8 * (int) b8) / (int) a8);
    

    符合要求的实现需要整数提升。默认情况下,一些嵌入式编译器不执行整数提升以提高代码密度(例如:MPLAB C18 编译器),但这些编译器通常也具有要符合的 ANSI 模式。

    现在对于 C,行为是用抽象机器来描述的,其中 优化问题是无关紧要的。如果编译器可以在不执行整数提升的情况下为程序实现相同的可观察行为,不这样做是免费的。

    假设你的 int 是 32 位的,你是对的,这个表达式:(a16 * b16) / a16 不能溢出。

    【讨论】:

      【解决方案2】:

      首先,我们有整数促销,6.3.1.1/2。脚注 58 说:

      整数提升仅适用于:作为通常算术转换的一部分,对于某些 参数表达式,一元 +、- 和 ~ 运算符的操作数,以及 移位运算符,由它们各自的子条款指定。

      其次,我们有常用的算术转换(6.3.1.8):

      [T]对两个操作数执行整数提升。然后 以下规则适用于提升的操作数:

      • 如果两个操作数的类型相同,则无需进一步转换。

      最后,我们有了运算符。例如,乘法表示 (6.5.5):

      对操作数执行通常的算术转换。

      因此,在表达式a8 * b8 中,两个操作数都通过整数提升提升为int,然后“不需要进一步转换”,因此表达式的结果也具有int 类型。

      【讨论】:

      • 您是从哪里获得晋升为int 的?他们都是in16_t
      • @GManNickG:根据int16_t 是什么,根据6.3.1.1/2 的整数提升是int(前提是它具有较低的转换等级)。的确,当int16_tlong int 的类型别名时,情况并非如此,但我切入了那个角落。
      • @GManNickG:标准规定如果int16_tint 的范围内,则将其提升为int
      • @KerrekSB int16_t 不能long的类型别名(在符合规范的实现中),后者必须至少有32位,前者需要正好有 16 个(没有填充位)。
      • @DanielFischer:是的,好点 :-)
      【解决方案3】:

      没有必要执行整数提升,如果没有它们的结果与使用整数提升的结果完全相同(这是 as-if 规则的一个实例,实现可以做任何它想做的事情,如果它与标准规定的方式无法区分)。

      算术运算符(6.5.5、6.5.6)的规范说整数提升是在操作数上执行的,因此您可以依赖“好像”。

      但是,您不能绝对确定 int16_t 操作不会溢出,因为 int 本身可能只有 16 位。

      【讨论】:

      • 抱歉,我已经澄清假设 int 是 32 位的。所以你是说如果它可能改变结果就需要整数提升,但如果它不会改变结果就不需要?
      • 对于抽象机,需要整数提升。如果实现可以实现与抽象机在不升级到int/unsigned int 的情况下产生的相同结果,例如使用具有二进制补码和环绕行为的本机 16 位类型,并且转换 int -> int16_t 是减少模 2^16,那么它实际上不需要转换为 int 进行计算。
      • @DanielFischer:同样值得注意的是,即使在积分促销不会影响任何 已定义 行为的情况下,该标准也会相当烦人地允许不需要的积分促销改变将被定义的内容行为转换为未定义行为。
      猜你喜欢
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多