作者:帆侮听我悄悄说星星 | 2023-08-28 20:25
我想在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)