C编译器是否假定有符号整数的加法是可交换的?

时间:2018-09-09 10:03:12

标签: c integer-overflow

我正在尝试检查签名加法是否会溢出。通常,要检查

int a + int b

会溢出(a和b都为正),我检查是否

if (a > INT_MAX - b)

但是现在我要检查

int a + int b - int c

会溢出。我知道a,b和c是正数,并且b> = c,所以我进行了以下检查:

if (a > INT_MAX - b + c)

现在我的问题是,编译器可以重写

INT_MAX - b + c     to     INT_MAX + c - b   ?

我担心的是,它首先将执行INT_MAX + c,这可能会溢出并导致不确定的行为。

3 个答案:

答案 0 :(得分:7)

在推理未定义的行为时考虑“编译器”的作用是谬论。编译器是透明的。该行为在您的代码中,而不在编译器中。您应该问:“ 我的代码 INT_MAX - b + c 平均是什么?它会溢出吗?答案永远不会在“编译器”中,而是在标准中。

该标准仅要求在程序中出现 单个操作不会溢出。对于任何未明确出现在程序中的重写表达式,它永远不会说任何话。 INT_MAX - b + c在您的程序中,并且等效于(INT_MAX - b) + c。因此,要求(INT_MAX - b)不会溢出,然后添加到c的结果也不会溢出。 INT_MAX + c - b没有出现在您的程序中,因此您不必担心它。

如果编译器以任何方式重写您的表达式,则必须确保根据 as-if 规则,重写后的表达式具有与您相同的可见行为。因此,如果确实将INT_MAX - b + c替换为INT_MAX + c - b,则必须确保不会发生溢出或将其透明地处理(例如,被硬件忽略)。

答案 1 :(得分:4)

表达式a - b + c等效于(a - b) + c。这是用该语言的语法编码的,此处最相关的子句是6.5.6:1(但当然,您必须查看整个语法才能理解此子句)。

      additive-expression:
             multiplicative-expression
             additive-expression + multiplicative-expression
             additive-expression - multiplicative-expression

面对a - b + c时,编译器只能将其解析为加法表达式a - b与乘法表达式c之和。没有其他规则可以适用。因此a - b + ca - bc的总和。

编译器可以自由生成它认为最适合您提供的源代码的汇编代码,但必须保留程序的含义。如果您编写了为a = INT_MAXb = 2c = 1定义的源代码,则汇编代码必须为这些值提供正确的答案。如果编译器选择对操作进行重新排序,则只会以保留含义的方式进行操作,例如,因为编译器知道目标体系结构的汇编指令会产生二进制补码结果,并且可以对其进行重新排序以得出相同的结果。

答案 2 :(得分:-4)

好吧,我们可以假设不可以。

但是"The C language standard doesn't specify operator precedence."

但是我要加上方括号,因为即使有轻微机会优先级也会搞砸。

来自https://stackoverflow.com/a/2722316/3268169的引用:

  
    

“编译器是由聪明的人建造的,可以做聪明的事情”,因此永远不会出错。

  
     

在胡说八道。

如果这是一个问题,那么也应该提高可读性。