Printf格式说明符和引号外的字段

时间:2018-01-16 15:30:49

标签: c printf

我遇到了以下代码:

#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)                                                                \   

我不明白s声明中printf在引号之外做了什么。我试着搜索它是什么以及它是如何工作的,但我不确定要寻找什么。有人可以向我解释这段代码是如何工作的吗?

作为后续工作,是否可以在宏外部编写如上例所示的代码?我见过的最接近的是使用格式说明符:

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

这将有助于理解这两个案例如何在内部工作,以及为什么C不允许我像上面的宏中那样做printf("%s" s "\n", string1, string2)之类的事情。

编辑:不是How does concatenation of two string literals work?的干净重复,因为这篇文章特定于printf(和格式说明符),因为它与宏有关。此外,在这篇文章的回复中有一些有用的信息在另一篇文章中没有。

3 个答案:

答案 0 :(得分:3)

  

我不明白在printf语句的引号之外s是做什么的

为了了解会发生什么,您需要回忆一下s被替换为程序文本中LOG宏的第二个参数。这可行的唯一方法是s字符串文字,因为C合并它们。换句话说,

之间没有区别
"quick brown fox"

"quick" " brown " "fox"

这两种写字符串文字的形式是等价的。

以同样的方式,将"ld"传递给<{p>中的FORMAT

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

相当于

printf("%ld\n", num);

并且是合法的。

  

为什么C不允许我像上面的宏那样做printf("%s" s "\n", string1, string2)之类的事情?

传递字符串文字以外的任何内容都是非法的:

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

sFORMAT必须不仅仅是字符串,而是字符串文字:

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

答案 1 :(得分:1)

"[%s] " s "\n"

s定义为宏时,即使用#define将所有内容连接在一起。

由于在预处理期间发生替换,因此不会将其标记为错误。在所有其他情况下,您应该收到语法错误。

答案 2 :(得分:0)

关键是线路延续&#39; \&#39;在定义的最后。该代码定义了一个宏函数LOG,它执行指定的日志记录。

显然,宏的用户可以在s中指定自己的格式化字符串,并在... - &gt;中提供参数。 ##__VA_ARGS_