旧笔记整理后发布

C99编译器允许可变参数宏(variadic macros), GCC默认使用的标准是GNU89/90标准,这个标准在C89的基础上增加了一些C99的功能(就比如这个Variadic macro)[^3]。

1
2
3
4
5
6
man gcc

...
gnu90
gnu89
GNU dialect of ISO C90 (including some C99 features). This is the default for C code.

查看gcc版本

1
gcc -E -dM - </dev/null | grep "STDC_VERSION"
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(void) {
#ifdef __STDC__
printf("%s\n", "stardard c");
#endif
#ifdef __STDC_VERSION__
printf("%d\n", __STDC_VERSION__);
#endif
return 0;
}

在这个版本中增加的宏__VA_ARGS__前增加##可以完成对逗号的处理,在没有传入额外参数时,gcc对代码进行预处理时,识别到##会将逗号给去除。如果不加入这个,那在不传入额外参数时,就会编译错误。[^4]

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <syslog.h>
#include <stdarg.h>
#include <stdio.h>
#define BUFF_LEN_O 1024
#define LOGGER(priority, format, ...) logger(priority, format, __FUNCTION__, __LINE__, ##__VA_ARGS__)

static void logger(int priority, const char *format, ...)
{
openlog("test_log", LOG_PID | LOG_NDELAY, LOG_LOCAL0);
va_list ap;
char buff[BUFF_LEN_O] = {0};
char placeholder[] = "function{%s},line{%d}";
va_start(ap, format);
snprintf(buff, sizeof(buff) - 1, "%s %s", placeholder, format);
vsyslog(priority, buff, ap);
va_end(ap);
}

int main()
{
printf("%s %d\n", __FUNCTION__, __LINE__);
LOGGER(LOG_INFO, "hello world %s", "123");
LOGGER(LOG_ERR, "new");
logger(LOG_INFO, "hello world %s", __FUNCTION__, __LINE__, "123");
return 0;
}

Reference

  1. C99 open-std.org/JTC1/SC22/WG14/www/docs/n897.pdf
  2. C11 ISO/IEC 9899:201x
  3. C Extensions - Using the GNU Compiler Collection (GCC)
  4. Variadic Macros - Using the GNU Compiler Collection (GCC)