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

C编译器是否假设有符号整数的加法是可交换的?,c,integer-overflow,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 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,这可能会溢出,并可能导致未定义的行为。

好吧,我们可以假设不会

但是

但我要加上括号,因为即使有轻微的机会,优先权也会搞砸

引自:

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

这是一场愚蠢的争论


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

在对未定义的行为进行推理时,考虑编译器的行为是错误的。编译器是透明的。行为在代码中,而不是在编译器中。你应该问我的代码INT_MAX-b+c是什么意思?它会溢出吗?答案永远不在编译器中,而是在标准中

该标准只要求程序中出现的单个操作不会溢出。它从不涉及任何未显式出现在程序中的重写表达式。INT_MAX-b+c在您的程序中,它相当于INT_MAX-b+c。所以要求INT_MAX-b不溢出,然后添加到c的结果不溢出。INT_MAX+c-b不会出现在您的程序中,因此您不应该担心它

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

表达式a-b+c相当于a-b+c。这是在语言的语法中编码的,这里最相关的子句是,但是当然你必须看整个语法才能理解这个子句

      additive-expression:
             multiplicative-expression
             additive-expression + multiplicative-expression
             additive-expression - multiplicative-expression
当面对a-b+c时,编译器只能将其解析为加法表达式a-b和乘法表达式c的和。没有其他规则可以适用。所以a-b+c是a-b的和,不管是什么,和c的和


编译器可以自由生成它认为最适合您提供的源代码的汇编代码,但它必须保留程序的含义。如果您编写了为a=INT_MAX、b=2和c=1定义的源代码,那么汇编代码必须为这些值提供正确的答案。如果编译器选择对操作重新排序,它将仅以保留意义的方式执行,例如,因为它知道目标体系结构的汇编指令会产生两个补码结果,并且可以重新排序以获得相同的结果。

如果您知道b>=c,然后简单地先计算b-c。我的问题更多的是关于是否允许编译器进行这样的优化。OP说a和b都是positive@KamilCuk:好的,我读过头了。但是为什么要使用有符号整数呢。这就是unsigned的作用。-和+有相同的顺序。@Tooonestforthis site是的,我的观点很模糊,很抱歉,我应该做更多的研究来支持这一点。这个答案似乎主张增加额外的保护措施,以防编译器中出现错误。坦率地说,这是荒谬的——如果编译器把运算符优先级这样的基本问题弄糟了,那么无论如何,它都会产生完全破坏的问题。如果在操作符优先级中有一个bug,那么处理括号中的bug可能会很容易,所以通过添加它们不会真正实现任何事情。@伊凡1这是一个C问题,所以C++是不相关的2,当C++指定了两个补码时,签名溢出仍然是未定义的。此函数仍将生成相同的代码@伊凡,你从哪儿弄来的?一家特定的软件公司可能对生产一个与其他公司不同的兼容C编译器不太感兴趣。那就不要使用他们的C编译器了。@Ivan是一个很好的编译器选择!所有这些编译器都应用了依赖于未定义签名溢出的优化,并且它们不会在C++20发布时停止。@Ivan一个不应用C标准编译C代码的编译器不是C编译器,end。我知道你提到过它。我要你展示一下。