M.M
M.M

Reputation: 141554

C preprocessor - define macro differently depending on another macro

I have a debugging setup where you set various debug flags in the makefile, and then in each source file we have:

#ifdef DEBUG_FLAG
#    define DEBUGGING(...) Something(__VA_ARGS__)
#else
#    define DEBUGGING(...) do {} while(0)
#endif

I would like to make this be more concise by having the source file say something like:

#define DEBUGGING(...) DEBUG_HELP( DEBUG_FLAG, Something(__VA_ARGS__) )

where DEBUG_HELP is defined in a header, with the same end result, i.e. using the DEBUGGING macro will cause Something to be called, only if DEBUG_FLAG was defined as non-zero. If DEBUG_FLAG was not defined at all then the code should still compile, just not call Something.

Is this possible at all?

My attempts so far, I have not been able to figure out a way to not get a compilation error in the case where DEBUG_FLAG was not defined at all.

Upvotes: 2

Views: 1055

Answers (2)

Joseph Quinsey
Joseph Quinsey

Reputation: 9962

Stealing from Nominal Animal's answer to a similar question, Test if preprocessor symbol is defined inside macro, the following should work. If foo.c is:

#define STRINGIFY(x) #x

#define DEBUG_HELP(flag, action)                      \
    do {                                              \
        if (strcmp(STRINGIFY(flag), #flag)) &&        \
            strcmp(STRINGIFY(flag), "0")) {           \
            action;                                   \
        }                                             \
    } while (0)

#define DEBUGGING(...) DEBUG_HELP(DEBUG_FLAG, printf(__VA_ARGS__))

DEBUGGING("%d\n", 42);

then:

$ gcc -E -P foo.c               
do { if (strcmp("DEBUG_FLAG", "DEBUG_FLAG")) && strcmp("DEBUG_FLAG", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG=0
do { if (strcmp("0", "DEBUG_FLAG")) && strcmp("0", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG  
do { if (strcmp("1", "DEBUG_FLAG")) && strcmp("1", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG=bar
do { if (strcmp("bar", "DEBUG_FLAG")) && strcmp("bar", "0")) { printf("%d\n", 42); } } while (0);

So with DEBUG_FLAG undefined or set to 0, the if condition will be false. And if DEBUG_FLAG is anything else, with one exception, the condition will be true. The one exception is when you have:

#define DEBUG_FLAG DEBUG_FLAG

The strcmp should all be evaluated at compile-time with gcc, Clang, and MSVC, although I cannot find any guarantee. As a test, see the following code:

#include <string.h>
int main(void) {
    if (strcmp("foo", "foo"))
        return 888;
    if (&"foo" != &"foo") // '&' for Clang
        return 999;
    return 777;
}

compiled here at https://godbolt.org/g/2kVShr.

Upvotes: 2

user694733
user694733

Reputation: 16043

You could have the condition in separate header file.

debug_help.h

#ifdef DEBUG_FLAG
    #define DEBUG_HELP(...) __VA_ARGS__
#else
    #define DEBUG_HELP(...) do {} while(0)
#endif

some_source_module.c

#include "debug_help.h"
#define DEBUGGING(...) DEBUG_HELP(puts(__VA_ARGS__))

DEBUGGING("test"); // expands to puts("test"); when DEBUG_FLAG is defined

You could omit the #include "debug_help.h" if you can have compiler auto-include it for each compilation unit.

Upvotes: 0

Related Questions