Без какой-либо оптимизации поток через ваш код является линейным. Если вы находитесь на 5-й строке и выполните один шаг, вы переходите к 6-й строке. При включенной оптимизации вы можете получить переупорядочение команд, развертывание цикла и все виды оптимизации.
Например:
void foo() {
1: int i;
2: for(i = 0; i < 2; )
3: i++;
4: return;
В этом примере без оптимизации вы можете пошагово пройти по коду и набрать строки 1, 2, 3, 2, 3, 2, 4
При включенной оптимизации вы можете получить путь выполнения, который выглядит следующим образом: 2, 3, 3, 4 или даже просто 4! (Функция ничего не делает ...)
Итог, отладка кода с включенной оптимизацией может быть королевской болью! Особенно если у вас большие функции.
Обратите внимание, что включение оптимизации меняет код! В определенных условиях (критические для безопасности системы) это недопустимо, и отлаживаемый код должен быть доставлен. В этом случае необходимо выполнить отладку с оптимизацией.
Хотя оптимизированный и неоптимизированный код должен быть «функционально» эквивалентным, при определенных обстоятельствах поведение изменится.
Вот упрощенный пример:
int* ptr = 0xdeadbeef; // some address to memory-mapped I/O device
*ptr = 0; // setup hardware device
while(*ptr == 1) { // loop until hardware device is done
// do something
}
С отключенной оптимизацией это просто, и вы знаете, чего ожидать.
Однако, если вы включите оптимизацию, может произойти пара вещей:
- Компилятор может оптимизировать блок while (мы устанавливаем 0, это никогда не будет 1)
- Вместо доступа к памяти, указатель доступа может быть перенесен в регистр-> Нет обновления ввода / вывода
- доступ к памяти может быть кэширован (необязательно связан с оптимизацией компилятора)
Во всех этих случаях поведение будет кардинально другим и, скорее всего, неправильным.