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

时间:2017-05-23 16:30:46

标签: c-preprocessor variadic-macros

我正在尝试编写一个C variadic宏,用于检查是否使用一个或多个参数调用它。

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

#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

分别

1 个答案:

答案 0 :(得分: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)的行为与其他情况不同(为您添加一个NL)(使用多个参数调用debug_log)......这会否定任何好处你获得了。

如果你以同样的方式拼写宏,它应该做同样的事情。让我只需要记住/使用(/转换)一个宏,然后强迫我根据我传递的参数来学习(/改变)如何使用它,让我受益,这只是在取笑我。 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)