g ++优化-O3导致奇怪的stackdump错误?

Shi*_*ari 1 c++ optimization stack-dump

首先,我2个月前才开始编程C/C++(但是有更多的Java经验),所以我对C/C++的经验很少.我正在撰写一篇论文,并正在使用/扩展为此目的而为之前的研究编写的其他代码.

现在,这个错误肯定是我遇到的最奇怪的事情,花了我差不多3个小时才找到并缩小到最基本的形式我可以用它来重现它.最后,我有以下代码的这两个文件

c.hh:

#ifndef C_HH_
#define C_HH_

class complex {
public:
    double re;
};
#endif
Run Code Online (Sandbox Code Playgroud)

test.cc:

#include <iostream>
#include "c.hh"

int main(int argc, char **argv) {
    complex* c;
    c->re = 0.0;

    for (int i = 0; i < 3; ++i) {
        c->re = (c->re) + (i==1)?0:1;
    }

    std::cout << c->re;
}
Run Code Online (Sandbox Code Playgroud)

我可以拿出的唯一一行仍然会出现错误,即c.re的初始化,即"c-> re = 0.0;".但是,我留下了这个,因为即使我删除代码的下半部分,如果没有这行,错误仍然会发生,因为c.re尚未初始化(或者我认为?).

我发现其他一切都是重现错误的必要条件,即

1)for循环.如果i = 1,2,3的行是单独写的,则不会导致错误.

2)我的极限!例如,如果我只从0到2运行,则不会导致错误.仅在至少3次迭代后才会发生.

3)显式赋值"c-> re =(c-> re)+",使用"+ ="而不是"=(c-> re)+"不会导致错误.

4)i"(i == 1)?0:1"的评估和(!)条件检查.使用if(..)执行此操作也会导致错误,但如果不使用i,则不会导致错误,或者不执行条件检查.

5)c.re的输出.即"std :: cout << c-> re;".简单地评估c.re("c-> re;")不会导致错误.如果只有输出而没有评估c.re,它也不会导致错误.通过"fprintf(stdout,"%d",c - > - re)执行相同操作;" 也会导致错误.

同样非常重要的是,只有在我编译代码时才会出现错误:

g++ -O3 -c -o test.o test.cc
g++ -O3 -o test test.o c.hh
Run Code Online (Sandbox Code Playgroud)

如果省略"-O3",它不会导致错误,所以我认为这是代码产生这个难以理解的错误的真正原因.注意使用-O3是因为正如我所提到的,这段代码是为研究编写的,其中这样的函数可能被调用了数百万次,因此最好尽可能地进行优化.然而,我只是根据给予我的内容调整了这个"惯例",并且不知道细节以及使用它的确切结果是什么.

最重要的是,每当出现错误时,程序根本不会运行.意思是,即使我在任何地方放置任何形式的输出,即使在代码的第一行,运行"test"也会立即导致错误而不输出任何内容.

最后,我在尝试执行程序"test"时遇到的错误如下:

0 [main] test 10720 cygwin_exception::open_stackdumpfile: Dumping stack trace to test.exe.stackdump
Run Code Online (Sandbox Code Playgroud)

stackdump文件包含以下内容:

Exception: STATUS_ACCESS_VIOLATION at eip=00401770
eax=00000001 ebx=0028CC8C ecx=8001801F edx=00000000 esi=0028CCA0 edi=0028CCA4
ebp=0028CC68 esp=0028CC50 program=D:\somepath\test\src\test.exe, pid 13768, thread main
cs=0023 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame     Function  Args
0028CC68  00401770 (00000001, 0028CC8C, 800280E8, 61007D35)
0028CD28  61007D9A (00000000, 0028CD84, 61006DC0, 00000000)
End of stack trace
Run Code Online (Sandbox Code Playgroud)

正如你可能能够告诉我我对这个问题非常迷茫并且不知道发生了什么,因为似乎没有任何编程上的"逻辑"理由来解释为什么会发生这种情况.在这个非常简单的代码中,我有什么问题吗?无论如何都要"解决"这个问题而不必忽略-O3优化?或者那可能不那么重要?

我希望我提供了足够的信息,感谢您的帮助!

pax*_*blo 10

complex* c;
c->re = 0.0;
Run Code Online (Sandbox Code Playgroud)

这是非常不确定的行为.第一行创建指向类型对象的指针,complex但实际上并不创建对象本身.指针将指向任意位置,因此解除引用它->是有问题的.

如果使用指针,则需要实际创建对象本身,然后将指针指向它.这就像更换一样简单:

complex *c;
Run Code Online (Sandbox Code Playgroud)

有:

complex *c = new complex();
Run Code Online (Sandbox Code Playgroud)

当然,你应该在完成后将它释放出来:

delete c;
Run Code Online (Sandbox Code Playgroud)

但是,这里不需要动态分配的对象,因为它的生命周期是严格本地的.你可以用以下方法证实一个对象:

object c;
Run Code Online (Sandbox Code Playgroud)

然后确保你使用.而不是->,例如:

c.re = 0.0;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,delete不需要.


此外,不要过多地阅读有关可能会产生与否的可能混淆情况的问题.

一旦你开始做未定义的事情,所有的赌注都关闭,程序几乎可以做任何想做的事情.

  • `complex c;`将是一个更简单的选项(作为一个java程序员,OP可能没有意识到这一点) (6认同)
  • @Hurkyl,是的,UB有时可以工作的事实是它最阴险的特征:-) (2认同)