Printf format specifier and fields outside quotes

I came across the following code:

#define ERROR 0
#define WARN 1
#define INFO 2
#define DEBUG 3  

extern int log_level;

char const *LEVEL_TO_STRING[] = { "ERROR", "WARN", "INFO", "DEBUG" };

#define LOG(level, s, ...)                                                  \
    do                                                                      \
    {                                                                       \
        if(level <= log_level)                                              \
            printf( "[%s] " s "\n", LEVEL_TO_STRING[level], ##__VA_ARGS__)  \
    }                                                                       \
    while(0)                                                                \   

I do not understand what the s is doing outside the quotes in the printf statement. I tried searching for what this is and how it works, but I’m not sure what to look for. Could someone explain to me how this code works?

As a follow-up, is it possible to write code like the example above outside a macro? The closest I’ve seen to this is using format specifiers:

#define FORMAT "ld"
long num = 1000000;
printf("%" FORMAT "\n", num);

It would help to understand how these two cases work internally, and why C does not let me do something like, printf("%s" s "\n", string1, string2) as is done in the macro above.

EDIT : Not a clean dup of How does concatenation of two string literals work? because this post is specific to printf (and format specifiers) as it relates to macros. Also, there is useful information in the responses to this post that isn’t available in the other.

Comments 3

  • I do not understand what the s is doing outside the quotes in the printf statement

    In order to see what happens you need to recall that s is replaced with the second parameter of LOG macro in the text of the program. The only way that this could work is when s is a string literal, because C merges them. In other words, there is no difference between

    "quick brown fox"
    

    and

    "quick" " brown " "fox"
    

    These two forms of writing a string literal are equivalent.

    In the same way, passing "ld" to FORMAT in

    printf("%" FORMAT "n", num);
    

    is equivalent to

    printf("%ldn", num);
    

    and is legal.

    why C does not let me do something like, printf("%s" s "n", string1, string2) as is done in the macro above?

    Passing anything other than a string literal is illegal:

    char FORMAT[] = "ld";
    printf("%" FORMAT "n", num); // <<== Does not compile
    

    s and FORMAT in your code must be not just strings, but string literals:

    #define s "[%s]"
    ...
    printf("%s" s "n", string1, string2); // This compiles
    
  • "[%s] " s "n"
    

    when s is defined as a macro ie using #define would concatenate everything together.

    As the substitution happens during the preprocessing, it won’t be flagged as an error. In all other cases, you should get a syntax error.

  • The key is the line continuation ” at the end of the definition. The code defines a macro function LOG which does the specified logging.

    Apparently the user of the macro can specify their own formatted string in s and give the arguments in ... -> ##__VA_ARGS_

发表评论

电子邮件地址不会被公开。 必填项已用*标注