【问题标题】:Good Verbosity Macro (C99)良好的详细度宏 (C99)
【发布时间】:2012-02-24 22:53:48
【问题描述】:

我正在寻找编写我认为是相当常见的宏。我想通过定义以下形式的一堆宏来模拟许多 POSIX 程序上重复的“-v”选项:

#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}

int main(int argc, char* argv[])
{
  // ... stuff ...
  int i = 1;
  V1("This contains a variable: %d\n",i);
}

// Output:
// ./program: This contains a variable: 1

其中optv 计算在命令行中找到的“-v”选项的数量,prog 包含程序名称(均未显示)。这很好用,但问题是我 必须 使用变量。 V1("Output") 将产生编译器错误。我总是可以使用V1("Output%s",""),但应该有更清洁的解决方案。

【问题讨论】:

  • 或者V1("%s", "Output")怎么样?
  • 这里似乎不需要宏。使用功能可以更轻松,更简单地完成它。例如,请参阅here

标签: c macros verbosity


【解决方案1】:

GNU C 预处理器有一个special feature,当没有填充可变参数部分的参数时,可以通过将标记粘贴运算符## 附加到__VA_ARGS__ 之前删除尾随逗号:

#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)

或者,如果您希望完全符合 C99,您可以将格式字符串参数合并到省略号中,但在这种情况下,您还需要重构代码,因为您想包含额外的 prog 参数在格式字符串和可变参数之间。这样的事情可能会起作用:

#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
    // Print out the program name, then forward the rest onto printf
    printf("%s: ", prog);

    va_list ap;
    va_start(ap, fmt);
    int ret = vprintf(fmt, ap);
    va_end(ap);

    return ret;
}

然后,V1("Output") 扩展为 myprintf(prog, "Output"),而不使用任何非 C99 编译器扩展。

编辑

还请注意,我在宏中反转了 if 条件,因为如果您在不带大括号的 if 语句中调用宏可能会出现一些奇怪的问题 - 有关详细说明,请参阅 this FAQ

【讨论】:

  • 我希望不需要实现一个功能,但根据其他答案,我似乎别无选择。
  • 转念一想,printf("%s: ",prog); 给了我一个好主意:#define V1(...) if(optv&gt;=1){printf("%s: ",prog);printf(__VA_ARGS__);}
  • 将类似函数的宏包装在 do while(0) 循环中可能会有所帮助
【解决方案2】:

为什么不为每个详细级别使用 2 个不同的宏;一个打印消息和变量,一个只打印消息?

【讨论】:

  • 因为我已经有 5 个详细级别,而且我也有相同的 == 版本。所以这意味着复制 10 个宏。
【解决方案3】:

您可能应该为自己编写一个小的支持函数,以便您可以干净地完成工作:

extern void vb_print(const char *format, ...);

#define V1(...)  do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)

我假设optvprog 都是全局变量。这些将进入标题(您不会将它们写在程序本身中,对吗?)。

函数可以是:

#include <stdio.h>
#include <stdarg.h>

extern const char *prog;

void vb_print(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    printf("%s:", prog);
    vprintf(format, args);
    va_end(args);
}

那里没有火箭科学。您可以根据自己的喜好调整系统,允许选择信息的写入位置、刷新输出、确保末尾有换行符等。

【讨论】:

    【解决方案4】:

    试试这个:

    #define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
    #define V1(...) V1X(__VA_ARGS__,0)
    

    我相信解决了您描述的问题,最后的else 解决了另一个问题。

    【讨论】:

    • 这不会生成有关格式字符串参数过多的警告吗?
    • 如果您启用了该警告,它可能会。在这种情况下,您可以使用"%s: "str"%.0d" :-)
    • 这样做的重点是删除过多的 args 警告,否则我只会V1("Output","") 并避免警告。
    • 另外,我有 5 个带有 == 和 >= 版本的详细级别,所以我不想再添加 10 个宏。
    • 使运算符甚至整个表达式成为宏 VXX 宏的参数...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    相关资源
    最近更新 更多