我正在尝试检查签名添加是否会溢出。一般来说,检查是否
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
没有出现在你的程序中,所以你不应该担心它。
如果编译器以任何方式重写表达式,则必须根据as-if规则确保重写的表达式与您的表达式具有相同的可见行为。因此,如果它确实用INT_MAX - b + c
替换INT_MAX + c - b
,它必须确保溢出要么不发生,要么透明处理(例如硬件忽略)。
表达式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
定义的源代码,那么汇编代码必须为这些值提供正确的答案。如果编译器选择重新排序操作,它只会以保留含义的方式执行,例如因为它知道目标体系结构的汇编指令产生两个补码结果并且可以重新排序以得到相同的结果。
好吧,我们可以假设没有。
但是"The C language standard doesn't specify operator precedence."
但我会在括号中添加,因为即使有一点点机会优先级也会陷入困境。
引自https://stackoverflow.com/a/2722316/3268169:
“编译器是由聪明人构建并做聪明的事情”因此,永远不会出错。
正在做一个愚蠢的论点。
如果这是一个问题,也应该增强可读性。