【问题标题】:How to create macro with different behavior depending on parameters number?如何根据参数编号创建具有不同行为的宏?
【发布时间】:2019-04-03 15:17:09
【问题描述】:

我想创建一个在有参数或没有参数时工作方式不同的宏。

例如:打印错误有两种不同的实现方式:

// 1. Print message = check code
#define PRINT_IF(wasError) \
    do { if (wasError) printf(#wasError); } while(false)

// 2. Throws an exception with formatted message
#define PRINT_TEXT_IF(wasError, format, ...) \
    do { if (wasError) printf(format, ##__VA_ARGS__); } while(false)

我想为这两种情况使用一个宏。

我尝试的是创建一个全局宏来检查它是否有参数,基于How to count the number of arguments passed to a function that accepts a variable number of arguments? 的方法。

#define RANDOM_GUID "5c300a82-2fe8-4bd3-ad12-ef13fa7b4a82"
#define FIRST_ARG(a1, ...) a1
#define HAS_ARGS(...) FIRST_ARG(##__VA_ARGS__, RANDOM_GUID)

#define GLOBAL_PRINT_IF(wasError, ...)             \
    do {                                           \ 
      if (wasError) {                              \
        if (HAS_ARGS(##__VA_ARGS__)==RANDOM_GUID ) \
          PRINT_IF(wasError);                      \
        else                                       \
          PRINT_TEXT_IF(wasError, __VA_ARGS__);    \
      }                                            \
    } while(false)

我假设因为FIRST_ARG 总是返回第一个参数,所以如果##__VA_ARGS__ 为空,它将返回RANDOM_GUID

但是这段代码不能用error: pasting "." and "red" does not give a valid preprocessing token 编译。 我曾尝试在__VA_ARGS__ 之前使用##,但使用expected primary-expression before ‘==’ token 失败了 排队

if (HAS_ARGS(__VA_ARGS__)==RANDOM_GUID )

那么,我做错了什么?如何正确处理?

【问题讨论】:

  • 由于您使用的是 C++,可变参数模板不是更适合这个吗?示例有点像你想要的底部:en.cppreference.com/w/cpp/language/parameter_pack
  • @HWalters 我将它从抛出异常更改为打印。现在它适合c 标签?
  • 首先了解如何获取可变参数宏here中的参数个数

标签: c macros c-preprocessor variadic-macros


【解决方案1】:
  1. 首先了解如何获取可变参数中的参数数量here
  2. 那么当你知道如何获取参数的数量时,你就可以轻松 检查此数字是否为 0

如果这是0,则此sn-p返回参数事件的数量:

#include <stdio.h>

#define PRINT(...)  (printf("%d\n", sizeof((int[]){__VA_ARGS__})/sizeof(int)))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}

很容易,第二个 sn-p 就完成了这项工作

#include <stdio.h>

#define PRINT(...)  (((sizeof((int[]){__VA_ARGS__})/sizeof(int))==0)?printf("do A\n"):printf("do B\n"))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}

【讨论】:

  • 实际上很难让“获取参数数量”返回 0,因为您实际上无法调用具有 0 个参数的宏——您只能使用通常会显示的空参数调用作为一个(空)论点。经过大量工作,您可以编写一个宏,如果使用单个空参数调用返回 0,否则返回参数的数量,但 OP 实际上并不需要它——他只需要知道 1 和 2 之间的区别或更多参数。
猜你喜欢
  • 1970-01-01
  • 2021-07-19
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-17
  • 2012-05-15
  • 1970-01-01
相关资源
最近更新 更多