引用临时变量 - 为什么编译器没有检测到它?

时间:2011-09-21 16:55:31

标签: c++ compiler-warnings undefined-behavior

我希望这不是重复,我已经阅读了一些相关的问题,但似乎没有人能够涵盖这个案例:

 #include <iostream>

int* return_dangling_p()
{
        int x = 1;
        return &x;  // warning: address of local variable 'x' returned
}

void some_func()
{
    int x = 2;
}

int main(int argc, char** argv)
{
    //  UB 1
    int* p = return_dangling_p();
    std::cout << *p;               // 1
    some_func();
    std::cout << *p;               // 2, some_func() wrote over the memory

    // UB 2
    if (true) {
        int x = 3;
        p = &x;     // why does compiler not warn about this?
    }
    std::cout << *p;    // 3
    if (true) {
        int x = 4;    
    }
    std::cout << *p;    // 3, why not 4?

    return 0;
}

我认为这是两个相同的未定义行为的情况。输出为1233,而我(天真地?)期望1234

所以我的问题是:为什么编译器在第二种情况下没有抱怨,为什么不像12那样重写堆栈?我错过了什么吗?

(MinGW 4.5.2,-Wall -Wextra -pedantic)

编辑:我知道讨论UB的输出毫无意义。我主要担心的是,如果有更深层次的原因可以解释为什么编译器会检测到一个而另一个没有。

2 个答案:

答案 0 :(得分:3)

  

为什么编译器没有在第二种情况下抱怨

我不确定。我想它可以。

  

为什么不像12

那样重写内存

这是未定义的行为。任何事情都可能发生。

请继续阅读,如果你真的好奇......

当我按原样编译你的代码时,我的编译器(g++ 4.4.3)将x中的两个UB 2变量放在堆栈的不同位置(我已通过查看验证了这一点)在拆卸)。因此,它们不会发生冲突,您的代码也会在此处打印出1233

但是,当我获取第二个x的地址时,编译器突然决定将其放在与第一个x相同的地址,因此输出更改为1234

if (true) {
    int x = 4;    // 3, why not 4?
    &x;
}

现在,这是我在没有任何优化选项的情况下编译时会发生的情况。我没有尝试过优化(在您的代码版本中,没有理由不能完全优化int x = 4。)

未定义行为的奇迹......

答案 1 :(得分:3)

我不确定编译器为什么不抱怨。我想这不是一个非常常见的用例,所以编译器的作者并不认为会为它添加警告。

在调用未定义的行为时,您无法推断出有关行为的有用信息。最终的输出可能是3,可能是4,或者可能是其他的。

[如果你想要解释,我建议看一下编译器生成的汇编程序。如果我不得不猜测,我会说编译器完全优化了最终if (true) { ... }。]