Оптимизация g ++ -O3 вызывает странную ошибку stackdump?

Во-первых, я только начал программировать на C / C ++ 2 месяца назад (но у меня больше опыта в Java), поэтому я далёк от опыта в C / C ++. Я работаю над диссертацией и использую / расширяю другой код, который был написан для предыдущих исследований с этой целью.

Теперь эта ошибка определенно самая странная, с которой я когда-либо сталкивался, и мне понадобилось почти 3 часа, чтобы найти и сузить до самой элементарной формы, с которой я мог бы воспроизвести ее … Наконец, у меня есть эти 2 файла со следующим кодом

c.hh:

#ifndef C_HH_
#define C_HH_

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

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

Единственная строка, которую я могу вынести, и ошибка все равно будет возникать, это инициализация 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) выход ц.ре. т.е. «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

Это не приведет к ошибке, если опустить «-O3», поэтому я полагаю, что это реальная причина, почему код выдаёт мне непонятную ошибку.
Обратите внимание, что -O3 используется, потому что, как я уже упоминал, этот код написан для исследований, в которых подобные функции могут вызываться миллионы раз, поэтому лучше всего оптимизировать как можно больше. Однако я только адаптировал эту «конвенцию» из того, что мне было дано, и на самом деле не знаю деталей и каков результат ее использования или нет.

Кроме того, всякий раз, когда возникает ошибка, программа не будет работать вообще. Смысл, даже если я положу любая форма вывода в любом месте, даже в самой первой строке кода, выполнение «test» немедленно вызовет ошибку и ничего не выдаст.

Наконец, ошибка, которую я получаю при попытке выполнить программу «test», заключается в следующем:

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

Где файл 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

Как вы могли бы сказать, я очень запутался в этой проблеме и понятия не имею, что происходит, так как не существует какой-либо программной «логической» причины того, почему это происходит.
Что-то я делаю не так в этом очень простом коде?
Есть ли способ «исправить» эту проблему, не пропуская оптимизацию -O3? Или это может быть не так важно?

Я надеюсь, что предоставил достаточно информации, спасибо за любую помощь!

1

Решение

complex* c;
c->re = 0.0;

Это очень неопределенное поведение. Первая строка создает указатель на объект типа complex но на самом деле не создает сам объект. Указатель будет указывать на произвольное местоположение, чтобы разыменовать его -> проблематично.

если ты хочу чтобы использовать указатель, вам нужно создать сам объект, а затем указать на него указатель. Это так же просто, как заменить:

complex *c;

с:

complex *c = new complex();

и, конечно, вы должны освободить его, когда закончите, с помощью:

delete c;

Тем не менее, нет необходимость для динамически размещенного объекта здесь, так как время жизни его строго локально. Вместо этого вы можете просто обосновать объект:

object c;

а затем убедитесь, что вы используете его с . скорее, чем ->, например, с:

c.re = 0.0;

В этом случае нет delete будет необходимо.


Кроме того, не читайте тоже в большей части вашего вопроса относительно возможных запутанных ситуаций, в которых он будет работать или нет.

Как только вы начинаете делать неопределенные вещи, все ставки прекращаются, и программа может делать все, что захочет.

10

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]