13

Let's say I want to have several types of output messages in my code. One of them is DEBUG, which is printed only, when the code is compiled in Debug mode.

Usually I'd have to write something like

#ifdef DEBUG
    std::cout << "Debug message" << std::endl;
#endif

which is pretty cumbersome and annoying to use in many places.

Is it a good practice to define a macro for the code snippet, so you'd use it this way?

MSG_DEBUG("Debug message")

Or is there any other, more elegant way how to deal with it without macros? I'm interested about possible solutions both in C and C++, as I'm using both languages in different projects.

Eenoku
  • 327
  • 1
  • 9
  • Possible duplicate of [How would you know if you've written readable and easily maintainable code?](https://softwareengineering.stackexchange.com/questions/141005/how-would-you-know-if-youve-written-readable-and-easily-maintainable-code) – gnat Sep 17 '18 at 08:23
  • It's not clear from the question why you wouldn't just put the conditional code in a function and call that. Is there some other constraint that would prevent that? – Alex Sep 17 '18 at 08:25
  • @gnat The question you've mentioned is so broad, that most people wouldn't connect it with this topic, especially when they'd be looking this specific question on the Internet. – Eenoku Sep 17 '18 at 08:27
  • @Alex Then there'd be a runtime overhead for every call of the function even if it does nothing, like in the case with the debug message. – Eenoku Sep 17 '18 at 08:28
  • 3
    Your question is tagged with both [tag:c] and [tag:c++], however, those are pretty different languages. Can you clarify which one you are talking about? Your example would be perfectly fine in C, but might be better implemented with a `constexpr if` in C++, for instance. – Jörg W Mittag Sep 17 '18 at 08:42
  • @JörgWMittag I'm interested in both of them. Would you mind to write a short answer about `constexpr if`? I have no experience using it. – Eenoku Sep 17 '18 at 08:43
  • 1
    As an aside, diagnostics should go to `STDERR`. Also, why not make it depend on `NDEBUG` like `assert()` does instead? Then you could define it like `#define DEBUG_MSG(MSG) assert(std::cerr << MSG)`, which tests the stream-state too. – Deduplicator Sep 17 '18 at 09:25

3 Answers3

19

Sure, if you're OK with using macros in the first place, then defining a parametrized one rather than keep repeating the same conditional code is certainly preferable by any measure of good coding.

Should you use macros at all? In my view you should, since it's accepted practice in C, and any macro-less solution would require at least something being executed even outside of debug mode. The typical C programmer will pick a slightly ugly macro over unnecessary run-time effort any time.

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
14

There's an element of personal preference here, but in C++ I prefer to do this in the header file:

#ifdef _DEBUG
    void DebugMessage(...);
#else
    inline void DebugMessage(...) {}
#endif

So that the function is inlined away in release builds, but is a proper function in the debug build so you can have proper type checking, sensible error messages, etc. and the ability to add further functionality (logging maybe?) later.

Obviously, you also need to encase the corresponding definition of the function in the .cpp file in an #ifdef _DEBUG block.

Martin Ba
  • 7,578
  • 7
  • 34
  • 56
Jack Aidley
  • 2,954
  • 1
  • 15
  • 18
  • But the call overhead is still present here, isn't it? – Eenoku Sep 17 '18 at 16:29
  • 7
    If your compiler will generate code to call a known empty function in a release build, the first and biggest thing you need to do to improve efficiency is get a much better compiler. This is really trivial optimization. – David Thornley Sep 17 '18 at 16:44
  • @Eenoku No, as David says, it'll be removed by any compiler you should use. – Jack Aidley Sep 17 '18 at 17:11
  • Could a C programmer comment on whether this method also functions in C? I don't use it myself. – Jack Aidley Sep 18 '18 at 07:16
  • 5
    There's a key difference here: the macro (depending on how it's written) would not evaluate its argument expressions, while the function always would. Also, it's undefined behavior to pass non-trivial arguments to varargs functions (and usually triggers compiler warnings). – Sebastian Redl Sep 18 '18 at 07:57
  • @SebastianRedl: I agree on your first point, that can be an issue if you have debug tracking code that is not defined in release, or have side effects in the calling code (although that is likely to be a problem with a macro too). Personally, I consider that a fair price to pay for the advantages of type checking, etc. On your second point, I intended the `...` as a placeholder for whatever arguments are wanted, this might be varargs or it might not. It's not an inherent difference of Macro vs. function since the macro will eventually be expanded to a function call anyway. – Jack Aidley Sep 18 '18 at 08:02
  • 1
    [This is also recommended by the Linux kernel coding style.](https://www.kernel.org/doc/html/latest/process/coding-style.html#conditional-compilation) – Matheus Moreira Sep 22 '18 at 22:50
2

Definitely, just make sure you're not stepping on the code guidelines given by your team. Make sure no other code in the system tries to reach the same functionality via a general if condition.

James O
  • 21
  • 3