Jul*_*mur 5 c c++ integer-overflow undefined-behavior
我正在阅读有关未定义行为的内容,我不确定它是否只是一个编译时功能,或者它是否可以在执行时发生.
我很好理解这个例子(这是从维基百科的未定义行为页面中提取的):
C语言的一个例子:
Run Code Online (Sandbox Code Playgroud)int foo(unsigned x) { int value = 5; value += x; if (value < 5) bar(); return value; }值
x不能为负,并且由于有符号整数溢出是C中未定义的行为,编译器可以假设在if检查行value >= 5.因此编译器可以忽略if和调用该函数bar,因为if它没有副作用,并且它的条件永远不会被满足.因此,上面的代码在语义上等同于:Run Code Online (Sandbox Code Playgroud)int foo(unsigned x) { int value = 5; value += x; return value; }
但这发生在编译时.
如果我写,例如:
void foo(int x) {
if (x + 150 < 5)
bar();
}
int main() {
int x;
std::cin >> x;
foo(x);
}
Run Code Online (Sandbox Code Playgroud)
然后用户键入MAX_INT - 100("2147483547",如果32位整数).
会有一个整数溢出,但是AFAIK,它是CPU 的算术逻辑单元会产生溢出,所以这里不涉及编译器.
它仍然是未定义的行为吗?
如果是,编译器如何检测溢出?
我能想到的最好的是CPU的溢出标志.如果是这种情况,是否意味着如果在执行时随时设置CPU的溢出标志,编译器可以执行他想要的任何操作?
是的,但不一定是我认为你可能意味着它的方式,也就是说,如果在机器代码中有一个添加,并且在运行时添加包装(或以其他方式溢出,但在大多数架构上它将包装)不是UB通过它自己.UB完全属于C(或C++)领域.这个添加可能是添加无符号整数或者是编译器可以进行的某种优化,因为它知道目标平台的语义,并且可以安全地使用依赖包装的优化(但你不能,除非你当然用无符号做类型).
当然,这根本不意味着使用"仅在运行时换行"的构造是安全的,因为这些代码路径在编译时也会中毒.例如,在您的示例中,
extern void bar(void);
void foo(int x) {
if (x + 150 < 5)
bar();
}
Run Code Online (Sandbox Code Playgroud)
由GCC 6.3编译,目标是x64
foo:
cmp edi, -145
jl .L4
ret
.L4:
jmp bar
Run Code Online (Sandbox Code Playgroud)
这相当于
void foo(int x) {
if (x < -145)
bar(); // with tail call optimization
}
Run Code Online (Sandbox Code Playgroud)
..如果你假设有符号整数溢出是不可能的,那就是相同的(在某种意义上它会在输入上放置一个隐含的前提条件,使得溢出不会发生).