I'm writing code (using GCC 4.7.2), where I'm excessively logging stuff during the testing phase in countless positions of the code. These loggings should disappear on the release binary.
I'm doing the logging via a function just like
void log(std::string msg);. As these function calls are many and distributed via the whole code in many files, I had the idea to make it an inline function and just give it an empty body for the release binary.
No my question is: what does the compiler do with it? Does the binary just contain the rest of the code without the function, does it contain a
nop, or anything else? Could I eliminate the logging code from the binary completely by emptying the inline logging function?
I'm not only interested in an answer to solve the problem but I'm also curious about the compiler's behaviour itself.
If you want different code between debug and release, then that's an ideal use case for the preprocessor:
#ifdef NDEBUG #define log(ignored) #endif
Then you're not leaving anything up to the compiler. You're guaranteed that only the debug version will have the extra calls. This is how
assert works, too.
Note that this will also drop the parameter computation. For example, if you have
log(get_msg()) then the macro method will drop the call to
get_msg() as well. This is probably desirable, but you need to be aware of it.
inline, that's entirely up to the compiler. The
inline keyword itself is only a hint, it does not obligate the compiler to do anything. The compiler performs its own optimization calculations on whether or not to inline a particular function (that includes inlining functions not marked
inline). That typically means a sufficiently high optimization level (i.e. -O3), and that the body of the inline function is visible in that particular compilation unit. For example, if the compiler only sees a declaration but the (maybe empty) function body is in a different .cpp file, then it cannot inline. But yes, if the compiler determines that there are no side effects, it is free to make the whole function disappear.
But again, there's no reason to depend on that when the preprocessor offers such a clean and widely used solution.
You might or might not be left with a trivially empty function (if for example, the function's address is used to make a pointer, then the function needs to exist).
But all inlined call sites will turn into nothing. (And the compiler should choose to always inline direct calls to a function it can see is empty -- Adam's answer is correct about calls into other translation units making this difficult, but Whole Program Optimization can help even there)
Do note, however, that parameters to an inline function will still be evaluated. They might also get inlined and mostly eliminated, but side effects in parameters will occur. This is rather different from using a
#define macro to eliminate the entire
log(...) string from the source code. The macro gets rid of the parameter computations, too.