Попробуйте сами:
$ g++ -O3 -S test.cpp -o test.s
-O3
включает оптимизацию, -S
указывает компилятору остановиться после генерации кода сборки, а -o
выбирает, где разместить выходные данные. Затем вы можете проверить файл "test.s" и посмотреть, оптимизировал ли он его или нет. Очевидно, что это требует определенных знаний по сборке. Вы также можете захотеть -masm=intel
, если вы, как и я, сочтете синтаксис AT & T нечитаемым и предпочитаете синтаксис Intel.
Это может помочь добавить строки типа asm("# this is something")
в код. Они будут отображаться как комментарии в сгенерированной сборке, что может упростить идентификацию интересующих вас частей.
На моей машине снимок GCC 4.8, похоже, не оптимизирует этот мертвый код. Я добавил один из этих asm-комментариев в каждую ветку, чтобы распознать их, и он сгенерировал это:
.file "test.cpp"
.intel_syntax noprefix
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "arg.arg is true\n"
.LC1:
.string "arg.arg is false\n"
.text
.p2align 4,,15
.globl _Z5thing4Args
.type _Z5thing4Args, @function
_Z5thing4Args:
.LFB1215:
.cfi_startproc
sub esp, 28
.cfi_def_cfa_offset 32
cmp BYTE PTR [esp+32], 0
jne .L6
#APP
# 13 "test.cpp" 1
This is the false branch
# 0 "" 2
#NO_APP
mov DWORD PTR [esp+8], 17
mov DWORD PTR [esp+4], OFFSET FLAT:.LC1
mov DWORD PTR [esp], OFFSET FLAT:_ZSt4cout
call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i
add esp, 28
.cfi_remember_state
.cfi_def_cfa_offset 4
ret
.p2align 4,,7
.p2align 3
.L6:
.cfi_restore_state
#APP
# 10 "test.cpp" 1
This is the true branch
# 0 "" 2
#NO_APP
mov DWORD PTR [esp+8], 16
mov DWORD PTR [esp+4], OFFSET FLAT:.LC0
mov DWORD PTR [esp], OFFSET FLAT:_ZSt4cout
call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i
add esp, 28
.cfi_def_cfa_offset 4
ret
.cfi_endproc
.LFE1215:
.size _Z5thing4Args, .-_Z5thing4Args
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB1216:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
and esp, -16
sub esp, 16
mov BYTE PTR [esp], 0
call _Z5thing4Args
xor eax, eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1216:
.size main, .-main
.p2align 4,,15
.type _GLOBAL__sub_I__Z5thing4Args, @function
_GLOBAL__sub_I__Z5thing4Args:
.LFB1367:
.cfi_startproc
sub esp, 28
.cfi_def_cfa_offset 32
mov DWORD PTR [esp], OFFSET FLAT:_ZStL8__ioinit
call _ZNSt8ios_base4InitC1Ev
mov DWORD PTR [esp+8], OFFSET FLAT:__dso_handle
mov DWORD PTR [esp+4], OFFSET FLAT:_ZStL8__ioinit
mov DWORD PTR [esp], OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
add esp, 28
.cfi_def_cfa_offset 4
ret
.cfi_endproc
.LFE1367:
.size _GLOBAL__sub_I__Z5thing4Args, .-_GLOBAL__sub_I__Z5thing4Args
.section .init_array,"aw"
.align 4
.long _GLOBAL__sub_I__Z5thing4Args
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.hidden __dso_handle
.ident "GCC: (GNU) 4.8.0 20120311 (experimental)"
.section .note.GNU-stack,"",@progbits
Если вы посмотрите на эти комментарии, вы найдете их оба с последующим вызовом некоторой std::cout
функции-члена.
Это происходит потому, что как есть, функция видна в других единицах перевода: если вы сейчас создаете файл nasty.cpp
с объявлением void thing(Args arg);
и вызовом со значением true
, код должен существует.
Так что я немного поэкспериментировал. Если я отмечу функцию как static
, что означает, что она является внутренней для этого модуля перевода, GCC действительно оптимизирует мертвый код:
.file "test.cpp"
.intel_syntax noprefix
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "arg.arg is false\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB1216:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
and esp, -16
sub esp, 16
#APP
# 13 "test.cpp" 1
This is the false branch
# 0 "" 2
#NO_APP
mov DWORD PTR [esp+4], OFFSET FLAT:.LC0
mov DWORD PTR [esp], OFFSET FLAT:_ZSt4cout
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
xor eax, eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1216:
.size main, .-main
.p2align 4,,15
.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1367:
.cfi_startproc
sub esp, 28
.cfi_def_cfa_offset 32
mov DWORD PTR [esp], OFFSET FLAT:_ZStL8__ioinit
call _ZNSt8ios_base4InitC1Ev
mov DWORD PTR [esp+8], OFFSET FLAT:__dso_handle
mov DWORD PTR [esp+4], OFFSET FLAT:_ZStL8__ioinit
mov DWORD PTR [esp], OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
add esp, 28
.cfi_def_cfa_offset 4
ret
.cfi_endproc
.LFE1367:
.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
.section .init_array,"aw"
.align 4
.long _GLOBAL__sub_I_main
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.hidden __dso_handle
.ident "GCC: (GNU) 4.8.0 20120311 (experimental)"
.section .note.GNU-stack,"",@progbits
В этом коде вы не найдете "Это истинная ветвь". Также обратите внимание, как ложная ветвь была перемещена в функцию main
, а функция thing
больше не существует. GCC просто вставил код функции и не стал его генерировать, потому что теперь он не будет использоваться где-либо еще, поскольку я добавил static
.
Если я отмечу его как inline
, он все равно будет виден снаружи, но, видимо, этого достаточно, чтобы GCC тоже оптимизировал его. Однако, если вы сделаете это, вам нужно будет убедиться, что другие единицы перевода увидят то же определение, чтобы можно было генерировать код для каждого из них.