变量宏,零参数

时间:2011-05-05 00:01:15

标签: c++ gcc c-preprocessor variadic-macros

我正在处理一个调用宏,

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), __VA_ARGS__))

当被叫时,

CALL(print,2,3,4,5);

将2 3 4 5添加到链接列表(,重载以执行此操作)并调用print,这需要一个按预期工作的链表,但是有些调用不需要参数,

CALL(HeapSize);

它仍然需要一个链接列表,但是空的一个,上面不起作用,我试图想出一个可以使用任何一种风格的宏吗?

编辑:通过gcc文档挖掘我发现在 VA_ARGS 之前添加##会删除,当没有参数但是我无法嵌套宏时,

CALL(print,CALL(HeadSize));

这会导致CALL未定义错误,如果我将其调用的调用分开

7 个答案:

答案 0 :(得分:19)

至于更新的问题,通过使用辅助宏VA_ARGS之类的 以下,参数将按预期展开。

#define VA_ARGS(...) , ##__VA_ARGS__
#define CALL(f,...) FN(f)->call((ref(new LinkedList()) VA_ARGS(__VA_ARGS__)))

答案 1 :(得分:10)

如果你正在使用gcc / g ++,有一种方法:

#define CALL(f,...) FN(f)->call((ref(new LinkedList()), ## __VA_ARGS__))

来自fine manual

  

[...]如果省略变量参数或为空,则`##'运算符会使预处理器删除前面的逗号。

因此,gcc专门针对您遇到的问题进行了扩展/黑客攻击。

答案 2 :(得分:4)

如果您正在使用GCC,它的扩展名可以吞掉__VA_ARGS__之前的逗号。请参阅:http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

答案 3 :(得分:1)

这些答案的一个共同主题是我们需要一个GCC特定的黑客。一种方法是使用token-paste ##__VAR_ARGS__,但粘贴的参数不是宏扩展的,这意味着宏不能嵌套。但是如果你打算做一些GCC特定的事情,那么为什么不使用老式的GCC扩展:

 #define VARARG_FOO(ZeroOrMoreArgs...) \
     printf("VARARG_FOO: " ZeroOrMoreArgs)

ZeroOrMoreArgs简单地被所有参数(如果有的话),逗号和所有参数替换。这包括递归宏扩展。

  • 然后VARARG_FOO()扩展为printf("VARARG_FOO: ")
  • VARARG_FOO("I iz %d", 42)扩展为printf("VARARGFOO: " "I iz %d", 42)

最后

 #define NEST_ME "I tawt I taw a puddy tat"
 VARARG_FOO("The evil one says %s", NEST_ME); 

将扩展为

 printf("VARARG_FOO: " "The evil one says %s", "I tawt I taw a puddy tat");

<强>优点:

  • 您可以嵌套宏调用,同时具有零或更多的基础。

<强>缺点:

  • ##__VA_ARGS__ hack 在标准C程序中可能无害,因为它们始终至少有一个逗号。 (我还没想过这是不是真的。)
  • 根据@ScootMoonen,##__VA_ARGS__ hack是MSVC的无证扩展。

答案 4 :(得分:0)

不幸的是,这无法做到。您需要定义一个单独的宏来执行此调用。

VA_ARGS 被替换为无效时,您最终会得到无效参数,最终会出现浮动,

#define CALL0(f) FN(f)->call((ref(new LinkedList())))

答案 5 :(得分:0)

只需将f作为...的一部分,然后使用单独的宏提取您需要的第一个参数f

答案 6 :(得分:0)

__VA_OPT__(c ++ 2a)应该更可靠,例如: 来自http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0306r2.html

  

VA_OPT 的规范用例用于可选的分隔符:

     

#define LOG(msg, ...) printf(msg __VA_OPT__(,) __VA_ARGS__)