Как говорит Пол, программа не имеет видимых побочных эффектов, и с включенной оптимизацией MSVC или любой из других основных компиляторов (gcc / clang / ICC) скомпилирует main
в простой xor eax,eax
/ ret
.Значение
i
никогда не выходит за пределы функции (не сохраняется в глобальном или возвращаемом), поэтому его можно полностью оптимизировать.И даже если бы это было так, постоянное распространение здесь тривиально.
Это просто изюминка / деталь реализации, которую анти-оптимизированный код MSVC в режиме отладки решает не испускать cmp/jcc
надпустое if
тело;даже в режиме отладки это не поможет при отладке.Это будет инструкция перехода, которая переходит на тот же адрес, на который она падает.
Смысл кода режима отладки в том, что вы можете пошагово пройти по исходным строкам и изменить Cпеременные с отладчиком.Не то чтобы asm был буквальной и точной транслитерацией C в asm.(А также то, что компилятор генерирует его быстро, не затрачивая усилий на качество, для ускорения циклов редактирования / компиляции / запуска.) Почему clang выдает неэффективный asm с -O0 (для этой простой суммы с плавающей запятой)?
Точность определения кода компилятора не зависит ни от каких языковых правил;не существует реальных стандартов, которые бы определяли, что компиляторы должны делать в режиме отладки, если фактически использовать инструкцию перехода для пустого if
тела.
Как видно из версии вашего компилятора, i++
post-increment было достаточно, чтобы компилятор забыл, что тело цикла пустое?
Я не могу воспроизвести ваш результат с MSVC 19.0 или 19.10 в проводнике компилятора Godbolt с 32или 64-битный режим .(VS2015 или VS2017).Или любая другая версия MSVC.Я не получаю никаких условных переходов от MSVC, ICC или gcc.
MSVC реализует i++
с фактическим сохранением в памяти для старого значения, как вы показываете, хотя.Так ужасно.GCC -O0
делает значительно более эффективный код режима отладки.Конечно, все еще довольно умная смерть, но в одном утверждении это иногда намного менее вредно.
Я могу воспроизвести его с помощью лязга, однако!(Но он разветвляется на оба if
с):
# clang8.0 -O0
main: # @main
push rbp
mov rbp, rsp
mov dword ptr [rbp - 4], 0 # default return value
mov dword ptr [rbp - 8], 0 # int i=0;
mov eax, dword ptr [rbp - 8]
add eax, 1
mov dword ptr [rbp - 8], eax
cmp eax, 4 # uses the i++ result still in a register
jne .LBB0_2 # jump over if() body
jmp .LBB0_2 # jump over else body, I think.
.LBB0_2:
mov eax, dword ptr [rbp - 8]
mov ecx, eax
add ecx, 1 # i++ uses a 2nd register
mov dword ptr [rbp - 8], ecx
cmp eax, 4
jne .LBB0_4
jmp .LBB0_4
.LBB0_4:
xor eax, eax # return 0
pop rbp # tear down stack frame.
ret