cmacrosc-preprocessorstringification

How to stringify char buffer for C macro


I have a LOG(fmt, ...) macro that does not work when using a char buf[] as fmt.

The code below is a complete (not actually) working example of the code. In some_function(), I am trying to use LOG() in two different ways but only the first approach works.

To solve the problem, I have tried using #define LOG_STR(x) #x in the following way:

  1. To stringify what is received in the #define LOG by applying LOG_STR() to format like this: LOG_STR(format); and

  2. To apply LOG_STR() directly to the printing like this: LOG(LOG_STR(fmt), 6).

Neither approach works and in fact I get segfault out of it.

    #include <stdio.h>

    #define LOG(format, ...) do {                             \
                fprintf(stderr, "[LOG] " format " [%s]\n",    \
                        ##__VA_ARGS__, __func__);             \
            } while (0)

    static void some_function()
    {
        // This works
        LOG("This is a number: %d", 5);

        // This does not work
        const char fmt[] = "This is a number: %d";
        LOG(fmt, 6);
    }

    int main(void)
    {
        some_function();
        return 0;
    }

When I compile the code above I get the following error:

$ gcc -o log-macro-str log-macro-str.c
log-macro-str.c: In function ‘some_function’:
log-macro-str.c:15:6: error: expected ‘)’ before ‘fmt’
  LOG(fmt, 6);
      ^
log-macro-str.c:4:29: note: in definition of macro ‘LOG’
    fprintf(stderr, "[LOG] " format " [%s]\n",    \
                             ^~~~~~

I'd like to use LOG() in both ways as done in some_function() or without modifiers and just printing a string. I suspect I might have to stringify the format part but I can't seem to do it correctly.

What am I doing wrong, and how can I solve this issue?


Solution

  • The stringify operator, # in a macro, converts preprocessor tokens to text in a string literal. It will not change the contents of a char buffer to a compile-time string literal.

    To make your macro work, use multiple fprintf statements:

    #define LOG(format, ...) do {                          \
                fprintf(stderr, "[LOG] ");                 \
                fprintf(stderr, format, __VA_ARGS__);      \
                fprintf(stderr, " [%s]\n", __func__);      \
            } while (0)