C语言宏定义多个可选参数

4

我正在尝试编写一个调试打印宏,该宏将打印函数名称,并具有包含格式/可变参数的选项,以便打印参数。

我已经设置了我的模块,使每个模块都有自己的打印颜色,通过为各个模块添加样式变量并在我的打印宏中使用它来实现。

以下是有效的打印宏:

//myprint.h
...
#define STYLE_UNDERLINE "\033[4m"
#define STYLE_NORMAL    "\033[0m"

#define STYLE_BLUE      "\033[0;34m"
... // more colo(u)rs here

#define PRINTF(fmt, ...) printf("%s" fmt STYLE_NORMAL, style, ##__VA_ARGS__)
...

使用方法:

//myfile.c
...
static char * style = STYLE_BLUE;

void myFunc(int i) {
    PRINTF("String with no params\n");
    PRINTF("i value %d\n", i);
}

我希望你能用一个 PRINT_FN 宏来实现类似的功能,使用方法如下:
//myfile.c
...

void myFunc(int i) {
    PRINT_FN();       // just print the function name
    // equivalent to
    PRINTF("%s%s()", STYLE_UNDERLINE, __func__);

    PRINT_FN("%d", i) // print the function name and parameter
    // equivalent to
    PRINTF("%s%s(%d)", STYLE_UNDERLINE, __func__, i);
}

我可以设计一个几乎可以实现这一目的的宏,问题在于需要您最少发送一个空格式字符串。

#define PRINT_FN(fmt, ...) printf("%s" STYLE_UNDERLINE "%s(" fmt ")" STYLE_NORMAL, \
                                  style, __func__, ##__VA_ARGS__)

有没有办法让fmt参数也变成可选的?

我只想把它称为 PRINT_FN() 而不是 PRINT_FN("")。 - user3817250
没有意义。它不会打印出一个新行。 - n. m.
@n.m. 我无法理解你的评论。你是在暗示所有的打印语句都需要换行符吗?最终我给我的 PRINT_FN 宏添加了一个换行符,但对于 PRINTF 并没有这样做。 - user3817250
1个回答

2
不要试图将所有内容都塞进一个printf语句中。应该将修饰符和实际输出分开:
#define PRINT_FN(...)                                   \
    do {                                                \
        printf("%s%s: ", STYLE_UNDERLINE, __func__);    \
        printf("" __VA_ARGS__);                         \
        printf("%s\n", STYLE_NORMAL);                   \
    } while (0)

如果格式为空,则将空字符串连接到空字符串,否则将其连接到原始格式。然而,gcc的-Wall设置会警告空格式字符串。

do ... while应该被编译掉,并用于使宏表现为一个语句。在您的情况下可能有些过度,但仍然有用。


或者,对于__VA_ARGS__可以使用snprintf,然后使用一个printf打印出完整的行。 - jxh
__VA_ARGS__ 前面还需要加上 ## 吗? - user3817250
@user3817250:不过,宏仅在第一个参数(如果有)为字符串字面值时才起作用,但这是类似于printf的函数的常见情况。(某些编译器甚至会警告您如果您没有指定字符串字面值。)gcc扩展, ##__VA_ARGS如果可变参数列表为空,则抑制逗号,但我们想要字符串连接。 - M Oehm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接