Встраивание указателя функции C++
Вопрос
Я знаю, что могу передать указатель на функцию в качестве параметра шаблона и получить к нему встроенный вызов, но мне было интересно, могут ли какие-либо компиляторы в наши дни встроить «очевидную» встроенную функцию, например:
inline static void Print()
{
std::cout << "Hello\n";
}
....
void (*func)() = Print;
func();
В Visual Studio 2008 он достаточно умен, чтобы свести его к инструкции прямого вызова, поэтому кажется позором, что он не может пойти дальше?
Решение
GNU g++ 4.5 встраивает его для меня, начиная с уровня оптимизации -O1.
main:
subq $8, %rsp
movl $6, %edx
movl $.LC0, %esi
movl $_ZSt4cout, %edi
call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_E
movl $0, %eax
addq $8, %rsp
ret
где .LC0 — это .string «Hello ».
Для сравнения: без оптимизации g++ -O0 он не встраивался:
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq $_ZL5Printv, -8(%rbp)
movq -8(%rbp), %rax
call *%rax
movl $0, %eax
leave
ret
Другие советы
В новых версиях GCC (4.4 и выше) есть опция -findirect-inlining.Если GCC может доказать себе, что указатель функции является константой, он выполняет прямой вызов функции или полностью встраивает функцию.
Ну, компилятор на самом деле не знает, будет ли эта переменная где-то перезаписана или нет (может быть, в другом потоке?), поэтому он допускает ошибку и реализует ее как вызов функции.
Я только что проверил VS2010 в выпускной сборке, и она не была встроена.
Кстати, вы украшаете функцию как inline
бесполезно.Стандарт гласит, что если вы когда-нибудь получите адрес функции, любой inline
подсказка будет проигнорирована.
редактировать:однако обратите внимание, что, хотя ваша функция не была встроена, переменная исчезла.В процессе разборки call
использует прямой адрес, он не загружает переменную в регистр и не вызывает ее.