空内联函数究竟会发生什么

What exactly happens to empty inline functions?

本文关键字:什么 究竟 函数      更新时间:2023-10-16

我正在编写代码(使用GCC 4.7.2),在测试阶段,我在代码的无数位置过度记录内容。这些日志应该在发布二进制文件中消失。

我通过一个类似void log(std::string msg);的函数进行日志记录。由于这些函数调用是多个的,并且通过许多文件中的整个代码进行分布,所以我想将其作为一个内联函数,并为发布二进制文件提供一个空的主体。

不,我的问题是:编译器用它做什么?二进制文件是否只包含没有函数的代码的其余部分,是否包含nop或其他内容?我可以通过清空内联日志记录函数来完全消除二进制文件中的日志记录代码吗?

我不仅对解决问题的答案感兴趣,而且对编译器的行为本身也很好奇。

如果您希望在调试和发布之间使用不同的代码,那么这是预处理器的理想用例:

#ifdef NDEBUG
#define log(ignored)
#endif

那么你就不会把任何东西留给编译器了。您可以保证只有调试版本才会有额外的调用。assert也是这样工作的。

请注意,这也将放弃参数计算。例如,如果您有log(get_msg()),那么宏方法也会放弃对get_msg()的调用。这可能是可取的,但你需要意识到这一点

至于inline,这完全取决于编译器。inline关键字本身只是一个提示,它并不要求编译器做任何事情。编译器对是否内联特定函数(包括未标记为inline的内联函数)执行自己的优化计算。这通常意味着一个足够高的优化级别(即-O3),并且内联函数的主体在特定的编译单元中是可见的。例如,如果编译器只看到一个声明,但(可能是空的)函数体在另一个.cpp文件中,则它不能内联。但是是的,如果编译器确定没有副作用,那么可以自由地使整个函数消失。

但是,当预处理器提供如此干净和广泛使用的解决方案时,没有理由依赖它。

您可能会也可能不会留下一个平凡的空函数(例如,如果函数的地址用于创建指针,则该函数需要存在)。

但是,所有内联调用站点都将变为空。(编译器应该选择始终内联直接调用一个它可以看到是空的函数——Adam的答案是正确的,即调用其他翻译单元会使这变得困难,但整个程序优化甚至可以在那里提供帮助)

但是,请注意,内联函数的参数仍将被求值。它们也可能被内联并大部分被消除,但参数中的副作用将发生。这与使用#define宏从源代码中删除整个log(...)字符串大不相同。宏也去掉了参数计算。