【问题标题】:How to create a C macro for appending /n to every printf如何创建一个 C 宏以将 /n 附加到每个 printf
【发布时间】:2016-02-05 21:50:34
【问题描述】:

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

【问题讨论】:

  • 问题是,printf 接受可变数量的参数,当您使用 (x) 时您没有考虑到这些参数,所以我认为该方案不会起作用
  • 只是对常识的呼吁:您首先尝试使用#define MY_PRINT printf 解决的问题到底是什么?

标签: c visual-studio macros printf


【解决方案1】:

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

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

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)

【讨论】:

    【解决方案2】:

    您希望您的宏能够接受各种参数,就像真正的 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);
    

    【讨论】:

      【解决方案3】:

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

      像这样定义你的宏

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

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

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

      【讨论】:

      • 这种方法的缺点是,如果您只使用格式字符串调用它,例如 MY_PRINT("string that doesn't have any arguments"),它将失败,因为 VA_ARGS 将扩展为 ,,从而导致语法错误(在确认平台上)。
      • @BeeOnRope 对我使用 MSVC 和 windows 来说效果很好。没有语法错误
      • 不同的编译器可以以不同的方式处理它。在 GNU CPP 中它会报告错误。令牌粘贴操作员将解决此问题。 #define MY_PRINT(format, ...) printf(format "\n", ##__VA_ARGS__) 详情请参考Variadic Macros
      猜你喜欢
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      相关资源
      最近更新 更多