Компилятор g ++: флаг оптимизации добавляет предупреждающее сообщение - PullRequest
6 голосов
/ 26 января 2010

Я заметил это интересное поведение компилятора g ++, если я добавлю флаг -O3 к компилятору, я получу

otsu.cpp:220: warning: ‘x’ may be used uninitialized in this function

Однако, когда я не использую оптимизацию и вместо этого использую флаг отладки -g, я вообще не получил никаких предупреждений. Теперь я больше доверяю компилятору, когда включен флаг -g; Тем не менее, мне интересно, если это хорошо определенное поведение, которое следует ожидать?

Для ясности код, вызывающий это, выглядит примерно так:

int x; //uninitialized


getAValueForX( &x ); // function makes use of x,
                     // but x is unitialized

, где

 void getAValueForX( int *x )
 {
     *x = 4;
 }

или что-то в этом роде, очевидно, более сложное.

Ответы [ 7 ]

16 голосов
/ 26 января 2010

Это ожидается. Оптимизация приводит к выполнению определенного анализа кода, и именно так gcc находит неинициализированные переменные. Это на странице руководства:

. , , эти предупреждения зависят от оптимизации

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

3 голосов
/ 27 января 2010

Анализ потока кода, который выполняет оптимизатор, позволяет обнаруживать потенциальные проблемы, которые не может обнаружить обычная (и более быстрая) компиляция. Проблема была всегда, компилятор просто не проверял ее.

Даже когда выдается это предупреждение, на самом деле это может не быть проблемой из-за фактического использования функции на практике; компилятор будет предполагать, что все возможные значения типов его аргументов (и любые внешние переменные, используемые в функции) могут встречаться во всех возможных комбинациях - приводя по крайней мере к одному пути, где переменная используется без присвоения значения. Ваше фактическое использование будет иметь гораздо более ограничительный набор возможных состояний, поэтому путь может никогда не возникнуть на практике. Простое решение - просто инициализировать переменную, чтобы отключить компилятор - это вам ничего не будет стоить.

Я всегда использую оптимизатор как форму статического анализа бедняка, даже когда в конечном итоге я не собираюсь использовать его в рабочем коде. Точно так же я часто использую более одного компилятора по той же причине. Некоторые компиляторы выполняют проверки, которые другие не выполняют, или генерируют сообщения с разными формулировками для одних и тех же ошибок, что часто помогает в их интерпретации для некоторых из более тупых сообщений.

Цитата:

Я доверяю компилятору больше, когда -g флаг включен

Хотя верно, что если в компиляторе есть ошибка, она, вероятно, будет в оптимизаторе (это самая сложная часть), но для зрелого компилятора, такого как GCC, это будет очень редкой находкой. Наоборот, люди часто обнаруживают, что их рабочий код не работает при оптимизации; чаще всего код всегда был ошибочным (возможно, он полагался на неопределенное или определенное компилятором поведение), и оптимизатор только что выявил этот недостаток. Поэтому я предлагаю, если вы обнаружите, что ваш код нарушается при оптимизации, подозревайте код перед компилятором - применяется Occam's Razor.

3 голосов
/ 26 января 2010

Это на самом деле очень часто встречается в gcc. И да, этого следовало ожидать.

Насколько я понял, для оптимизации компилятор генерирует много метрик и преобразует код (или, точнее, его представление в код) таким образом, который позволяет обнаруживать неинициализированные или неиспользованные переменные для примеров (есть еще несколько подобных предупреждений, я не помню список).

Чтобы сделать то же самое без оптимизации, потребовалось бы выполнить, а затем отказаться от всего этого анализа. Это значительно замедлило бы компиляцию без какой-либо цели (тем более, что при отладке компилятор не должен перестраивать код).

1 голос
/ 26 января 2010

Ну, тот факт, что компилятор может перемещать вещи для оптимизации, может вызвать проблемы и привести к неопределенному поведению (как указано в руководстве ниже); Я думаю, что было бы полезно увидеть код, чтобы попытаться помочь разобраться.

Ярлыки, используемые оптимизированным кодом может иногда вызывать удивление Результаты: некоторые переменные, которые вы объявили может вообще не существовать; поток контроля может ненадолго переместиться туда, где вы этого не сделали ожидать этого; некоторые утверждения не могут быть выполняется потому, что они вычисляют константу результаты или их значения уже были под рукой; некоторые операторы могут выполняться в разных местах, потому что они были вышел из петель.

1 голос
/ 26 января 2010

Да, это четко определенное поведение. Когда оптимизатор GCC не включен, он не выполняет определенные типы проверки пути выполнения (чтобы избежать снижения производительности при выполнении таких проверок). Определенные ситуации, такие как использование неинициализированных переменных, могут быть обнаружены только при выполнении этих дополнительных проверок. Следовательно, с -O0 GCC не может предупреждать об этих условиях.

1 голос
/ 26 января 2010

Флаги моего компилятора:

CFLAGS=-W -Wall\
 -Wno-non-template-friend\
 -Wold-style-cast\
 -Wsign-promo\
 -Wstrict-null-sentinel\
 -Woverloaded-virtual
# -Weffc++

-Weffc ++ может сильно раздражать, поэтому иногда я пробую, но обычно держу его выключенным. Попробуйте это - и другие в руководстве - и давайте посмотрим, что мы видим.

0 голосов
/ 27 января 2010

У меня такая же проблема в моем компиляторе msvc 6. Инициализация рассматриваемой переменной устраняет возможность неверного пути с точки зрения компилятора.

...