检查可变参数宏是否有一个与多个参数?

Check if variadic macro has one vs many arguments?

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

我找到了一些使用宏来计算参数的解决方案,但这些解决方案要么针对 fixed/finite 个参数,要么依赖于共享相同类型的参数:

#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

分别

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

#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) ......这会抵消你获得的任何好处。

如果你用同样的方式拼写宏,它应该做同样的事情。让我只需要 remember/use(/transform) 一个宏,然后强迫我根据我传递的参数来学习(/更改)如何使用它,这对我有利,这只是在逗我。 debug_log 应该总是 为我添加一个 NL,或者它应该 从不 添加一个。

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

在这种情况下,强制加入 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)