当前位置:  开发笔记 > 编程语言 > 正文

如何制作可变参数宏(可变数量的参数)

如何解决《如何制作可变参数宏(可变数量的参数)》经验,为你挑选了4个好方法。

我想在C中编写一个宏,它接受任意数量的参数,而不是特定的数字

例:

#define macro( X )  something_complicated( whatever( X ) )

哪里X有任何数量的参数

我需要这个,因为它whatever是重载的,可以用2或4个参数调用.

我试过两次定义宏,但第二个定义覆盖了第一个!

我正在使用的编译器是g ++(更具体地说,mingw)



1> Alex B..:

C99方式,也由VC++编译器支持.

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)


`##`不需要,也不便携.`#define FOO(...)printf(__ VA_ARGS __)`以便携方式完成工作; `fmt`参数可以从定义中省略.
__VA_ARGS__之前##的原因是,如果变量参数列表为空,它会吞下前面的逗号,例如.FOO("a")扩展为printf("a").这是gcc(也许是vc ++)的扩展,C99要求至少有一个参数代替省略号.
## - 语法也适用于llvm/clang和Visual Studio编译器.所以它可能不是便携式的,但主要编译器支持它.
我不认为C99在__VA_ARGS__之前需要##.那可能只是VC++.
IIRC,##是GCC特定的,允许传递零参数
如果您想在宏中使用这些参数并且不使用printf或其他采用变量args的函数,该怎么办?

2> cmccabe..:

__VA_ARGS__是标准的方法.如果您不需要,请不要使用特定于编译器的黑客攻击.

我真的很生气,我无法对原帖发表评论.在任何情况下,C++都不是C的超集.使用C++编译器编译C代码真的很愚蠢.不要做Donny不做的事.


*"使用C++编译器编译C代码真的很愚蠢"*=>每个人(包括我)都不这么认为.参见例如C++核心指南:**CPL.1:首选C++到C**,[**CPL.2:如果必须使用C,请使用C和C++的公共子集,并将C代码编译为C++**](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rcpl-subset).我捉襟见肘想起了什么,"C-仅-主义"人真正需要,使其价值的兼容子集不是编程,以及C和C++委员会已经在做的是兼容子集可用功.
对于真正的跨平台系统项目(例如操作系统),您确实要坚持使用严格的C语言,因为C编译器更为常见。在嵌入式系统中,仍然存在没有C ++编译器的平台。(有些平台只有合格的C编译器!)C ++编译器让我感到紧张,尤其是对于网络物理系统,我想我不是唯一有这种感觉的嵌入式软件/ C程序员。
@HostileFork足够公平,但*当然*C++人员希望鼓励使用C++.但是其他人不同意; 例如,Linux Torvalds显然拒绝了多个提议的Linux内核补丁,这些补丁试图用`klass`替换标识符`class`以允许用C++编译器进行编译.另请注意,有一些差异会让你失望; 例如,三元运算符在两种语言中的评估方式不同,而`inline`关键字意味着完全不同(正如我从另一个问题中学到的).

3> eduffy..:

我不认为这是可能的,你可以用双parens伪造它...只要你不需要单独的参数.

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))


虽然可以使用可变参数宏,但使用双括号是一个很好的建议.

4> 小智..:
#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

如果编译器不了解可变参数宏,您还可以使用以下任一方法去掉PRINT:

#define PRINT //

要么

#define PRINT if(0)print

第一个注释掉PRINT指令,第二个注释因为条件为NULL而阻止PRINT指令.如果设置了优化,编译器应该删除从未执行过的指令,如:if(0)print("hello world"); 或((无效)0);


#define PRINT //不会用//替换PRINT
#define PRINT if(0)print不是一个好主意,因为调用代码可能有自己的else-if调用PRINT.更好的是:#define PRINT if(true);否则打印
标准的"无所事事,优雅地"是做{}而(0)
推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有