当前位置:  开发笔记 > 编程语言 > 正文

在执行时上溢/下溢是否为未定义的行为?

如何解决《在执行时上溢/下溢是否为未定义的行为?》经验,为你挑选了1个好方法。

我正在阅读有关未定义行为的内容,我不确定它是否只是一个编译时功能,或者它是否可以在执行时发生.

我很好理解这个例子(这是从维基百科的未定义行为页面中提取的):

C语言的一个例子:

int foo(unsigned x)
{
    int value = 5;
    value += x;
    if (value < 5)
        bar();
    return value;
}

x不能为负,并且由于有符号整数溢出是C中未定义的行为,编译器可以假设在if检查行value >= 5.因此编译器可以忽略if和调用该函数bar,因为if它没有副作用,并且它的条件永远不会被满足.因此,上面的代码在语义上等同于:

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);
}

然后用户键入MAX_INT - 100("2147483547",如果32位整数).

会有一个整数溢出,但是AFAIK,它是CPU 的算术逻辑单元会产生溢出,所以这里不涉及编译器.

它仍然是未定义的行为吗?

如果是,编译器如何检测溢出?

我能想到的最好的是CPU的溢出标志.如果是这种情况,是否意味着如果在执行时随时设置CPU的溢出标志,编译器可以执行他想要的任何操作?



1> harold..:

是的,但不一定是我认为你可能意味着它的方式,也就是说,如果在机器代码中有一个添加,并且在运行时添加包装(或以其他方式溢出,但在大多数架构上它将包装)不是UB通过它自己.UB完全属于C(或C++)领域.这个添加可能是添加无符号整数或者是编译器可以进行的某种优化,因为它知道目标平台的语义,并且可以安全地使用依赖包装的优化(但不能,除非你当然用无符号做类型).

当然,这根本不意味着使用"仅在运行时换行"的构造是安全的,因为这些代码路径在编译时也会中毒.例如,在您的示例中,

extern void bar(void);

void foo(int x) {
    if (x + 150 < 5)
         bar();
}

由GCC 6.3编译,目标是x64

foo:
        cmp     edi, -145
        jl      .L4
        ret
.L4:
        jmp     bar

这相当于

void foo(int x) {
    if (x < -145)
         bar(); // with tail call optimization
}

..如果你假设有符号整数溢出是不可能的,那就是相同的(在某种意义上它会在输入上放置一个隐含的前提条件,使得溢出不会发生).


@Kadriles我不会这么说,因为无论编译器做什么,UB都在那里.但是这种行为在实践中是无辜的,如果它不是编译器参与,这实际上使这个错误更糟糕:在未经优化的调试版本中,像这样的代码通常不会出现它的问题.
推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有