我正在尝试检查签名加法是否会溢出。通常,要检查
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,这可能会溢出并导致不确定的行为。
答案 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 + c
是a - b
和c
的总和。
编译器可以自由生成它认为最适合您提供的源代码的汇编代码,但必须保留程序的含义。如果您编写了为a = INT_MAX
,b = 2
和c = 1
定义的源代码,则汇编代码必须为这些值提供正确的答案。如果编译器选择对操作进行重新排序,则只会以保留含义的方式进行操作,例如,因为编译器知道目标体系结构的汇编指令会产生二进制补码结果,并且可以对其进行重新排序以得出相同的结果。
答案 2 :(得分:-4)
好吧,我们可以假设不可以。
但是"The C language standard doesn't specify operator precedence."
但是我要加上方括号,因为即使有轻微机会优先级也会搞砸。
来自https://stackoverflow.com/a/2722316/3268169的引用:
“编译器是由聪明的人建造的,可以做聪明的事情”,因此永远不会出错。
在胡说八道。
如果这是一个问题,那么也应该提高可读性。