空内联函数到底发生了什么?

时间:2014-02-09 09:35:54

标签: c++ inline

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

我正在通过void log(std::string msg);之类的函数进行日志记录。由于这些函数调用很多,并且通过许多文件中的整个代码进行分发,因此我有了使其成为内联函数的想法,并为释放二进制文件赋予它一个空体。

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

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

2 个答案:

答案 0 :(得分:5)

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

#ifdef NDEBUG
#define log(ignored)
#endif

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

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

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

但同样,当预处理器提供如此清晰且广泛使用的解决方案时,没有理由依赖它。

答案 1 :(得分:3)

你可能会或可能不会留下一个简单的空函数(例如,如果函数的地址用于制作指针,那么函数需要存在)。

但是所有内联呼叫网站都将变成一无所有。 (并且编译器应该选择始终内联直接调用它可以看到的函数是空的 - Adam的答案对于调用其他翻译单元是正确的,这使得这很困难,但整个程序优化甚至可以帮助)

但请注意,仍将评估内联函数的参数。它们也可能被内联并且大部分被淘汰,但参数中的副作用将会发生。这与使用#define宏从源代码中消除整个log(...)字符串完全不同。宏也摆脱了参数计算。