简体   繁体   English

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

[英]g++ optimization -O3 causing strange stackdump error?

First off, I only started programming C/C++ 2 months ago (but have more experience in Java) so I am far from experienced in C/C++. 首先,我是2个月前才开始进行C / C ++编程(但是有更多的Java经验),所以我对C / C ++的经验还远远不够。 I'm working on a thesis and am using/expanding other code that has been written for previous research for that purpose. 我正在撰写论文,并且正在使用/扩展为此目的先前编写的其他代码。

Now, this error is definitely the strangest I have yet encountered and took me almost 3 hours to find and narrow down to the most elementary form i could reproduce it with.. Finally, I have these 2 files with the following code 现在,此错误绝对是我遇到的最奇怪的错误,我花了将近3个小时才找到并缩小到可以用来重现的最基本的形式。.最后,我用下面的代码创建了这2个文件

c.hh: c.hh:

#ifndef C_HH_
#define C_HH_

class complex {
public:
    double re;
};
#endif

test.cc: 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;
}

The only line I could take out and the error will still occur is the initialization of c.re, ie "c->re = 0.0;". 我能取出的唯一一行错误仍然会发生,是c.re的初始化,即“ c-> re = 0.0;”。 However, I left this in because even if i remove the lower part of the code the error would still occur without this line, because c.re has not been initialized (or so i think?). 但是,我将其保留在其中是因为即使我删除了代码的下半部分,如果没有此行,仍然会发生错误,因为c.re尚未初始化(或者我认为呢?)。

Everything else I found to be neccessary to reproduce the error, ie 我发现需要重做该错误的其他所有内容,即

1) the for loop. 1)for循环。 Will not cause an error if the lines for i=1,2,3 are written seperately. 如果i = 1,2,3的行分别写入,将不会导致错误。

2) the limits of i! 2)我的极限! eg will not cause an error if i only runs from 0 to 2. only occurs after at least 3 iterations. 例如,如果我仅从0到2运行,则不会导致错误。仅在至少3次迭代之后才会发生。

3) the explicit assignment "c->re = (c->re) +", using "+=" instead of "= (c->re) +" will not cause the error. 3)使用“ + =”代替“ =(c-> re)+”的显式赋值“ c-> re =(c-> re)+”不会导致错误。

4) the evaluation and(!) conditional check of i "(i==1)?0:1". 4)i的评估和(!)条件检查“(i == 1)?0:1”。 Using if(..) to do this also causes the error, but it causes no error if i is not used, or no conditional check is performed. 使用if(..)执行此操作也会导致错误,但是如果不使用i或不执行条件检查,则不会导致错误。

5) the output of c.re. 5)c.re的输出 ie "std::cout << c->re;". 即“ std :: cout << c-> re;”。 Simply evaluating c.re ("c->re;") does not cause an error. 简单评估c.re(“ c-> re;”)不会导致错误。 It also does not cause an error if there is just an output without evaluating c.re at all. 如果只有一个输出而根本不评估c.re,那么它也不会导致错误。 Doing the same via "fprintf(stdout, "%d", c->-re);" 通过“ fprintf(stdout,”%d“,c->-re);进行相同的操作 also causes the error. 也会导致错误。

Also very important is that the error only occurs if I compile the code like this: 同样非常重要的是,仅当我编译如下代码时才会发生错误:

g++ -O3 -c -o test.o test.cc
g++ -O3 -o test test.o c.hh

It will not cause an error if "-O3" is omitted, so I figure this is the real reason why the code produces this to me incomprehensible error. 如果省略“ -O3”,则不会导致错误,因此我认为这是代码对我产生不可理解的错误的真正原因。 Note the -O3 is used because as I mentioned this code is written for research where functions like this might be called up to millions of times, so it is best to optimize as much as possible. 请注意,使用-O3是因为正如我提到的那样,此代码是为研究而编写的,此类函数可能被调用多达数百万次,因此最好尽可能地进行优化。 I have however only adapted this "convention" from what has been given to me and don't really know the details and what exactly the result of using it, or not, are. 但是,我只是根据提供给我的内容改编了该“惯例”,并不真正了解细节以及使用或不使用它的确切结果。

On top of that, whenever the error is caused, the program will not run at all . 最重要的是,每当导致错误时,程序将根本不会运行 Meaning, even if I put any form of output anywhere, even at the very first line in the code, running "test" will immediately cause the error and not output anything. 意思是,即使我在任何地方(在代码的第一行)都放置了任何形式的输出 ,运行“ test”将立即导致错误并且不输出任何内容。

Finally, the error i get upon trying to execute the program "test", is the following: 最后,尝试执行程序“ test”时遇到的错误如下:

0 [main] test 10720 cygwin_exception::open_stackdumpfile: Dumping stack trace to test.exe.stackdump

Where the stackdump file contains the following: 其中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

As you might be able to tell I am very lost with this issue and have no idea what is going on, as there doesn't seem to be any programmatically "logic" reason as to why this happens. 如您所知,这个问题让我感到非常迷茫,不知道发生了什么,因为似乎没有任何编程上的“逻辑”原因来说明这种情况的发生。 Is there anything I'm doing wrong in this very simple code? 在这个非常简单的代码中我有做错什么吗? Is there anyway to "fix" this issue without having to leave out the -O3 optimization? 无论如何,是否有必要“修正”这个问题而不必忽略-O3优化? Or is that maybe not that important? 还是那不那么重要?

I hope I provided enough information, thanks for any help! 希望我提供了足够的信息,感谢您的帮助!

complex* c;
c->re = 0.0;

This is very much undefined behaviour. 这是非常不确定的行为。 The first line creates a pointer to an object of type complex but doesn't actually create the object itself. 第一行创建一个指向类型为complex的对象的指针,但实际上并未创建该对象本身。 The pointer will point to an arbitrary location so that dereferencing it with -> is problematic. 指针将指向任意位置,因此使用->对其进行引用是有问题的。

If you want to use a pointer, you need to actually create the object itself then point the pointer to it. 如果使用指针,则需要实际创建对象本身,然后将指针指向该对象。 This is as simple as replacing: 这就像替换一样简单:

complex *c;

with: 与:

complex *c = new complex();

and you should of course free it when you're done, with: 并且您当然应该在完成后使用以下命令释放它:

delete c;

However, there's no need for a dynamically allocated object here since the lifetime of it is strictly local. 但是,这里不需要动态分配的对象,因为它的生存期严格是本地的。 You could instead just substantiate an object with: 您可以改为通过以下方式证实对象:

object c;

and then ensure you use it with . 然后确保将其用于. rather than -> , such as with: 而不是-> ,例如:

c.re = 0.0;

In that case, no delete would be required. 在这种情况下,将不需要delete


In addition, don't read too much into the bulk of your question regarding the possibly confusing situations in which it will work or not. 此外,关于问题可能无法解决的情况,请不要过多地阅读。

Once you start doing undefined things, all bets are off and the program can pretty much do whatever it wants. 一旦开始做未定义的事情,所有的赌注都将消失,该程序几乎可以做任何想做的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM