【问题标题】:Check if variadic macro has one vs many arguments?检查可变参数宏是否有一个对多个参数?
【发布时间】:2017-05-23 16:30:46
【问题描述】:

我正在尝试编写一个 C 可变参数宏来检查它是使用一个参数还是多个参数调用的。

我发现了一些使用宏来计算参数的解决方案,但这些解决方案要么用于固定/有限数量的参数,要么依赖于共享相同类型的参数:

#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

将参数计数到 10,然后失败。但是我认为检查 1 与多个参数是一个更容易的问题,因此它可能有一个适用于任何类型和任何数量参数的解决方案。

我对此的用途是一种debug_log 宏:

#define debug_log(...) \
    do { \
        fprintf(verbose, " - %lu ", time(NULL)); \
        if (VA_HAS_MANY_ARGS(__VA_ARGS__)) { \
            fprintf(verbose, __VA_ARGS__); \
        } else {
            fprintf(verbose, "%s\n", __VA_ARGS__); \
        } \
    while (0)

可以调用debug_log("string here");,也可以调用debug_log("string there %i\n", 5);,并将生成:

- current_time_here string here\n
- current_time_there string there 5\n

分别。

【问题讨论】:

  • 对于导致this细节不使用完全不使用可变参数宏的问题可能有更好的解决方案...
  • 看起来像 XCY 问题。您尝试解决的实际问题是什么?不要太喜欢宏!
  • @Olaf 我有一个调试宏,例如:#define debug_log(...) do { fprintf(verbose, " - %lu %s\n", time(NULL), __VA_ARGS__); } while(0) 工作正常,但缺少可变参数。我想要的是一个宏,我可以用debug_log("whatever string");debug_log("whatever format string %i\n", 5); 调用它,它会分别产生:“-current_time_here 任何字符串\n”、“-current_time_here 任何格式字符串5\n”。
  • 听起来很糟糕而且容易出错。是什么让您无法使用两个不同的宏?
  • “但是我认为检查 1 和多个参数是一个更容易的问题” ...好奇...如果你知道如何做 A,但你不知道如何做 B,那么您基于什么推测 B 比 A 容易?

标签: c-preprocessor variadic-macros


【解决方案1】:

以下是您可以编写一个或多个宏的方法:

#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(A,B,...) B
#define SHIFT_IN_ZERO , 0
#define ONE_OR_MANY_UTILITY(...) ONE_OR_MANY_UTILITY_I(__VA_ARGS__, SHIFT_IN_ZERO, X)
#define ONE_OR_MANY_UTILITY_I(A,B,...) B
#define ONE_OR_MANY(...) SECOND(ONE_OR_MANY_UTILITY(__VA_ARGS__), 1)

但是,请注意,这是一个相当复杂的宏系统(比 VA_NARGS 更复杂),我不确定您在问题的用例中是否从中受益(我认为这是问题的一部分)。

你本质上试图完成的事情对我来说似乎被误导了。您想将各种用法合并为一个宏,debug_log;这本身就是一种多态性。这是一个收获。但是,您特别试图使其中一种情况(使用一个参数调用 debug_log)与其他情况(使用多个参数调用 debug_log)表现不同(为您添加一个 NL)......这否定了任何好处你得到了。

如果你以同样的方式拼写宏,它应该做同样的事情。让我只需要记住/使用(/转换)一个宏,然后根据我传递的参数数量强迫我学习(/更改)如何使用它,这让我受益匪浅,这只是在取笑我。 debug_log 应该总是为我添加一个 NL,或者它应该从不添加一个。

最好使用两个不同的宏,因为它们做两种不同的事情。但是,最好将这些宏合并为一个始终执行相同操作的宏。

在这种情况下,强制 NL 进入可能是个好主意;这有助于确保您的日志文件本身可用。但是,当您使用一个参数调用它时,不要添加 NL,而使用多个参数调用时不会添加,为什么不总是添加 NL?:

#define debug_log(...) \
    do { \
         /* fprintf metadata--timestamp, file, log level, etc here */ \
         fprintf(verbose, __VA_ARGS__); \
         fputs("\n", verbose); \
        } \
    while (0)

【讨论】:

  • 谢谢!我最终完成了您指定的 debug_log 宏,但由于它并没有真正解决问题,所以我没有发布它。
猜你喜欢
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
相关资源
最近更新 更多