如何创建用于将 /n 附加到每个 printf 的 C 宏

How to create a C macro for appending /n to every printf

MY_PRINT是贯穿整个代码的一个宏,它只是做printf。 我想暂时修改它以在每个 printf 之后也附加 \n。

但是,当我这样做时:

#define SENS_PRINT(x)        printf(x);   printf("\n")
MY_PRINT( "\n   #%d:  %c    ", ++command_line_number, sensor_operation_code );

...输出是垃圾:#3405240: <alpha symbol>

打印正常,但末尾没有 \n:

#define SENS_PRINT   printf

函数行宏的问题在于预处理将所有以逗号分隔的参数视为宏的参数,而不是单个参数。所以你的编译器真的应该抱怨你向宏传递了很多参数。

一个简单的解决方案是将宏参数括在括号中:

MY_PRINT( ( "\n   #%d:  %c    ", ++command_line_number, sensor_operation_code ) );
//        ^                                                                   ^
//        |                                                                   |
// Note extra parentheses here...                                      and here

另一个解决方案是使用variadic macros


在某种程度上相关的注释中,如您所示,您的宏不能用于构造,例如

if (some_condition)
    MY_PRINT(...);

那将被替换为

if (some_condition)
    printf(...);
printf(...);

如果宏中有多个语句,则需要将其包含在一个块中,例如

#define MY_PRINTF(...) \
    do {               \
        statement1;    \
        statement2;    \
        .              \
        .              \
        .              \
        statementN;    \
    } while (0)

您希望您的宏能够接受各种参数,就像真正的 printf 一样。您可以使用可变参数宏来做到这一点。

当宏是条件代码块中的唯一表达式时,两个单独的表达式不会被解释为宏建议的也存在危险。想想如果你说 if (flag) SENS_PRINT(...); 宏会做什么。防止这种情况的一种方法是将宏包装在 do { ... } while(0) 块中。

将换行符附加到 printf 的可变参数宏可能如下所示:

#define PRINTFLN(...) do { printf(__VA_ARGS__); puts(""); } while (0)

你可以像printf一样使用它:

PRINTFLN("Hello %s!", "cruel world");
if (flag) PRINTFLN("%d + %d == %d", x, y, sum);

C 语言允许您连接由空格分隔的字符串文字。如果您对 MY_PRINT 的所有调用都使用字符串文字作为它们的格式参数,您可以定义一个可变参数宏,它将直接将 "\n" 附加到您的格式字符串,然后应用其余参数。

像这样定义你的宏

#define MY_PRINT(format, ...) printf(format "\n", __VA_ARGS__)

您将能够直接将换行符附加到格式化参数。

使用此方法只会执行一个函数调用,但任何使用字符串文字以外的任何格式的调用都会导致编译错误。