Это довольно стандартно в программной инженерии в целом - когда вы оптимизируете код, компилятору разрешается перестраивать вещи практически так, как он хочет, до тех пор, пока вы не можете заметить разницу в работе. Так, например, если вы инициализируете переменную внутри каждой итерации цикла и никогда не изменяете переменную внутри цикла, оптимизатору разрешается вывести эту инициализацию из цикла, чтобы вы не тратили на нее время.
Возможно, вы поймете, что вы вычисляете число, с которым потом ничего не делаете, прежде чем переписывать. В этом случае это может устранить бесполезные вычисления.
Проблема с оптимизацией заключается в том, что вы захотите поставить точку останова на некоторый фрагмент кода, который оптимизатор переместил или исключил. В этом случае отладчик не может делать то, что вы хотите (как правило, он ставит точку останова где-то близко). Таким образом, чтобы сделать сгенерированный код более похожим на то, что вы написали, вы отключаете оптимизации во время отладки - это гарантирует, что код, который вы хотите взломать, действительно существует.
Вы должны быть осторожны с этим, однако, в зависимости от вашего кода, оптимизация может сломать вещи! В общем случае код, который нарушается корректно работающим оптимизатором, на самом деле является просто ошибочным кодом, который сходит с рук, поэтому вам обычно нужно выяснить, почему оптимизатор его нарушает.
Я отправил этот вопрос Джеку Гэнслу, и вот что он мне ответил:
источник
Зависит, и это в целом верно для всех инструментов, не только C30.
Оптимизации часто удаляют и / или реструктурируют код различными способами. Ваш оператор switch может быть переопределен конструкцией if / else или в некоторых случаях может быть удален все вместе. y = x * 16 может быть заменено серией левых сдвигов и т. д., хотя этот последний тип оптимизации, как правило, все еще можно пройти, в основном это реструктуризация оператора управления, которая получает ya.
Это может сделать невозможным пошаговое выполнение отладчиком вашего кода C, поскольку структуры, которые вы определили в C, больше не существуют, они были заменены или переупорядочены компилятором в нечто, что, по мнению компилятора, будет быстрее или займет меньше места. Это также может сделать невозможным установку точек останова из списка C, так как инструкция, по которой вы взломали, больше не существует. Например, вы можете попытаться установить точку останова внутри оператора if, но компилятор, возможно, удалил ее, если. Вы можете попытаться установить точку останова в цикле while или for, но компилятор решил развернуть этот цикл, чтобы он больше не существовал.
По этой причине, если вы можете отлаживать с отключенной оптимизацией, это обычно проще. Вы всегда должны перепроверять с оптимизацией на. Это единственный способ узнать, что вы пропустили важное,
volatile
и оно вызывает периодические сбои (или некоторые другие странности).В случае разработки встраиваемых систем, вы все равно должны быть осторожны с оптимизацией. В частности, в тех разделах кода, которые критичны по времени, например, некоторые прерывания. В этих случаях вы должны либо кодировать критические биты в сборке, либо использовать директивы компилятора, чтобы убедиться, что эти разделы не оптимизированы, чтобы вы знали, что у них фиксированное время выполнения или фиксированное время выполнения в худшем случае.
Другая проблема может заключаться в том, чтобы встраивать код в ОК, вам может потребоваться оптимизация плотности кода, чтобы просто вставить ваш код в чип. Это одна из причин, почему обычно лучше начинать с наибольшей емкости ПЗУ в семействе и выбирать только меньшую для производства, после того как код заблокирован.
источник
Как правило, я бы отлаживал с любыми настройками, которые планировал выпустить. Если бы я собирался выпустить оптимизированный код, я бы отладил с оптимизированным кодом. Если бы я собирался выпустить неоптимизированный код, я бы отладил неоптимизированный код. Я делаю это по двум причинам. Во-первых, оптимизаторы могут вносить достаточно существенные различия во времени, чтобы конечный продукт вел себя не так, как неоптимизированный код. Во-вторых, хотя большинство из них довольно хороши, производители компиляторов допускают ошибки, а оптимизированный код может давать разные результаты из неоптимизированного кода. В результате я хотел бы получить как можно больше времени для тестирования при любых настройках, с которыми я планирую выпустить.
При этом оптимизаторы могут затруднить отладку, как отмечалось в предыдущих ответах. Если я нахожу определенный фрагмент кода, который трудно отладить, я временно выключу оптимизатор, выполню отладку, чтобы код заработал, затем снова включу оптимизатор и снова протестирую.
источник
Моя обычная стратегия состоит в том, чтобы развиваться с окончательной оптимизацией (макс. Для размера или скорости в зависимости от ситуации), но временно отключить оптимизацию, если мне нужно отладить или отследить что-либо. Это снижает риск появления ошибок в результате изменения уровней оптимизации.
Типичный режим отказа - когда увеличение оптимизации приводит к появлению ранее невидимых ошибок из-за того, что вы не объявили переменные как изменчивые там, где это необходимо - важно сообщить компилятору, какие вещи не следует «оптимизировать».
источник
Используйте любую форму, которую вы собираетесь выпустить, отладчики и компиляция для отладки скрывают множество ошибок, которые вы не видите, пока не скомпилируете для выпуска. К тому времени гораздо труднее найти эти ошибки, чем отлаживать по ходу работы. 20 с лишним лет, и у меня никогда не было использования gdb или другого подобного отладчика, нет необходимости наблюдать за переменными или одним шагом. От сотен до тысяч строк в день. Так что это возможно, не нужно думать иначе.
Компиляция для отладки, а затем компиляция для релиза может и займет от двух до более чем двухкратных усилий. Если вы попали в привязку и должны использовать такой инструмент, как отладчик, то скомпилируйте его для работы с конкретной проблемой, а затем вернитесь к нормальной работе.
Другие проблемы также актуальны, так как оптимизатор ускоряет выполнение кода, поэтому для встраивания, в частности, изменений во времени с помощью параметров компилятора, и это может повлиять на функциональность вашей программы, здесь снова используется выбор компиляции с доставкой на протяжении всей фазы. Компиляторы тоже программы, и в них есть ошибки, а оптимизаторы допускают ошибки, а некоторые не верят в это. Если это так, то нет ничего плохого в том, что он компилируется без оптимизации, просто делайте так все время. Путь, который я предпочитаю, - это компилировать для оптимизации, тогда, если я подозреваю, что проблема с компилятором отключает оптимизацию, если это исправляет ее, обычно возвращаются назад и вперед, иногда исследуя вывод ассемблера, чтобы выяснить, почему.
источник
Я всегда разрабатываю код с -O0 (опция gcc отключает оптимизацию). Когда я почувствую, что я нахожусь в точке, где я хочу начать выпускать вещи, я начну с -Os (оптимизация по размеру), поскольку, как правило, чем больше кода вы можете сохранить в кэше, тем лучше, даже если он не супер оптимизирован.
Я считаю, что GDB намного лучше работает с кодом -O0, и намного легче следовать, если вам нужно войти в сборку. Переключение между -O0 и -Os также позволяет вам увидеть, что компилятор делает с вашим кодом. Время от времени это довольно интересное обучение, и оно также может выявить ошибки компилятора ... те неприятные вещи, которые заставляют вас напрячься, пытаясь выяснить, что не так с вашим кодом!
Если мне действительно понадобится, я начну добавлять в -fdata-секции и -fcode-секции с помощью --gc-секции, которые позволяют компоновщику удалять целые функции и сегменты данных, которые фактически не используются. Есть много мелочей, с которыми можно повозиться, чтобы попытаться уменьшить или ускорить процесс, но в целом это единственные приемы, которые я в конечном итоге использую, и все, что должно быть меньше или быстрее, я передам -assemble.
источник
Да, отключение оптимизаций во время отладки уже давно является лучшей практикой по трем причинам:
Многие люди идут еще дальше в этом направлении и грузят с включенными утверждениями .
источник
Все просто: оптимизация требует много времени и может оказаться бесполезной, если вам придется изменить этот фрагмент кода позже в процессе разработки. Так что они вполне могут быть пустой тратой времени и денег.
Однако они полезны для готовых модулей; части кода, которые, скорее всего, больше не будут нуждаться в изменениях.
источник
это, безусловно, имеет смысл в случае точек останова ... так как компилятор может удалить множество операторов, которые на самом деле не влияют на память.
рассмотреть что-то вроде:
может быть полностью оптимизирован (потому что
i
никогда не читается). с точки зрения вашей точки останова будет выглядеть, что он пропустил весь этот код, когда его в принципе просто не было ... Я предполагаю, что именно поэтому в функциях типа сна вы часто будете видеть что-то вроде:источник
Если вы используете отладчик, я бы отключил оптимизацию и включил отладку.
Лично я считаю, что отладчик PIC вызывает больше проблем, чем помогает мне исправить.
Я просто использую printf () для USART для отладки моих программ, написанных на C18.
источник
Большинство аргументов против включения оптимизации в вашей компиляции сводятся к:
ИМХО первые два законны, третий не так уж и много. Это часто означает, что у вас плохой код или вы полагаетесь на небезопасную эксплуатацию языка / реализации, или, может быть, автор просто фанат доброго дяди Undefined Behavior.
В блоге Embedded in Academia есть кое-что, что можно сказать о неопределенном поведении, и этот пост о том, как его используют компиляторы: http://blog.regehr.org/archives/761
источник