3

I've been inspecting someone's code and I encountered this:

#else //If not in Debug mode

#define LOG_WARNING(str) do { (void)sizeof(str); } while(0)
#define LOG_INFO(str) do { (void)sizeof(str); } while(0)

// ... More #define directives

#endif

Apparently, do { (void)sizeof(str); } while(0) is carefully written so the directive can be completely ignored by the compiler.

How does this work?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • Looks like an elaborate version of `( void )str ;`. – 2501 Jan 06 '15 at 14:10
  • does http://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for help? – Luchian Grigore Jan 06 '15 at 14:14
  • @LuchianGrigore That doesn't have any meaning here. Looks like the author was overly cautious. – 2501 Jan 06 '15 at 14:15
  • @LuchianGrigore I know how `do { ... } while(0)` works when used on #define directives. However, what I do not know is why adding `(void)sizeof(str)` makes it ignored by the compiler – Matias Cicero Jan 06 '15 at 14:20
  • @2501 Does `(void)str` achieves the same effect? Do you know how it works? I'm really interested – Matias Cicero Jan 06 '15 at 14:21
  • @MatiCicero what do you mean by "ignored by the compiler"? `sizeof` doesn't evaluate the argument, and `(void)` is just a cast. What do you expect? – Luchian Grigore Jan 06 '15 at 14:24
  • @MatiCicero It suppresses the unused warning. – 2501 Jan 06 '15 at 14:29
  • Using ((void)str) is boilerplate. But you can come up with plenty of "does nothing" snippets, the optimizer removes the dead code. If you #include Windows.h, common in a MSVC++ project, then you can use the built-in macros like UNREFERENCED_PARAMETER() – Hans Passant Jan 06 '15 at 14:29
  • @MatiCicero `(void)str` would still evaluate `str`. `(void)sizeof(str)` doesn't. – T.C. Jan 06 '15 at 15:05
  • See [C `#define` macro for debug printing](http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing/1644898#1644898). It forces the compiler to validate `str` whether the code is compiled for debugging or not — which reduces the risk of staleness creeping into your code. – Jonathan Leffler Jan 06 '15 at 15:18

1 Answers1

4

The operand of sizeof is an unevaluated, so this ensures that there is no work to be done at run time. The macro just ignores a constant value; the compiler can see that it has no effect, so should generate no code from it.

The advantage over doing nothing at all is that the compiler still checks that the argument is a valid expression; you won't accidentally break the debug build when changing the code and only compiling for release.

The advantage over (void)str, mentioned in the comments, is that that would evaluate the expression, and the compiler might not be able to eliminate it, since it there might be side effects. For example:

extern std::string get_message(int code);
LOG_INFO(get_message(code));  // -> (void)get_message(code);

in a release build would call the function and ignore the result, impacting performance.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644