Подтвердить что ты не робот

Зачем компилировать с -O2 вместо -O3

Обычно мы компилируем с помощью -O2, потому что -O3 будет "запускать тонкие ошибки".

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

Учитывая, что ошибки в нашем коде на порядок более вероятны, чем ошибки компилятора, и что мы используем -Wall -Wextra без каких-либо проблем, какие ошибки мы должны искать?

Если это имеет значение, мы используем gcc-4.3.2. Время компиляции для нас не является серьезной проблемой.

4b9b3361

Ответ 1

Размер. Конечно, если размер действительно имеет значение (иногда есть, например, встроенный), можно использовать -Os. Но главное отличие в O3 - это (от вас уже упоминалось) вложение. Это может увеличить генерируемый размер кода (но быстрее). Может быть, вам нужна скорость, но вовсе не (космос)? В противном случае я не вижу причин, почему бы не использовать O3 (кроме того, что вы знаете о компиляторе gcc, который встречается только в вашем коде на O3, но до тех пор, пока у вас нет ошибки, вы не можете воспроизвести на O2, мне все равно).

Ответ 2

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

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

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

Обычно такой код выглядит как

 while( keepGoing ){
      doStuff();
 }

Затем значение keepGoing изменяется другим. Ну, одна оптимизация, которую JVM будет делать, показывает, что keepGoing не модифицируется в цикле, поэтому он "поднимает" его и проверяет перед внешним видом, по существу:

 if( keepGoing ){
      while( keepGoing ){
           doStuff();
      }
 }

Что в многопоточной среде не одно и то же, а однопоточное. Это те вещи, которые могут нарушить оптимизацию. Это частой источник Heisenbugs.

PS. В Java правильным ответом является make keepGoing "volatile", поэтому он не может использовать кешированные значения и будет делать то, что вы хотите.

Ответ 3

Не обманывайте себя, что ошибки компилятора не скрываются там, чтобы сделать вашу адскую жизнь. Здесь противный, который появился в Debian в прошлом году, и где исправление должно было вернуться к -O2.