我在分析代码时碰到了下面的宏。
#define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra)
函数name
作为参数传递给__COMMAND_HANDLER
但是代码中的其他任何地方都没有定义此函数。定义了cmd参数的类型(command_invocation
)。基本上我无法理解这个宏的功能,因为我找不到函数name
的定义。名称是标准C库中的某种预定义函数吗?如果未定义name
,此宏定义是否有意义?
答案 0 :(得分:1)
Durning预处理,预处理器将所有出现的__COMMAND_HANDLER(name, extra ...)
宏替换为其主体,并将其身体内name
和extra...
的每个出现替换为您指定的标记。
这意味着在这种情况下,无论您为name
参数输入什么,它都将是一个函数名称,extra...
将是第一个参数旁边的附加参数(struct command_invocation *cmd
)。
例如以下一行:
__COMMAND_HANDLER(foo, int param) {
/* definition */
}
预处理后的将是:
int foo(struct command_invocation *cmd, int param) {
/* definition */
}
必须澄清一件重要的事情:##
之前的extra
和命名变量参数(使用extra...
而不是...
)不是{{##
的一部分3}}标准,但它们是c。逗号后-pedantic
的效果允许您为变量参数指定任何内容。使用GCC(带/* The following example will print the following messages:
* warning: ISO C does not permit named variadic macros [-Wvariadic-macros]
* warning: ISO C99 requires at least one argument for the "..." in a variadic
* macro
*/
__COMMAND_HANDLER(bar);
标志)编译示例时,如下所示,您将看到警告消息:
##
通常##
是令牌连接的运算符,即#include <stdio.h>
#define FOO(name, number) void name##number()
FOO(bar, 1) { puts("I'm first."); }
FOO(bar, 2) { puts("I'm second."); }
int main() {
bar1();
bar2();
return 0;
}
运算符两侧的两个标记组合成一个标记。例如:
registerCourse
答案 1 :(得分:0)
这是一个宏,名称是一个参数。 你这样使用它:
__COMMAND_HANDLER(hello, char* world)
在预处理阶段,它会将您的代码转换为:
int hello(struct command_invocation *cmd, char *world);
在这种情况下,name作为hello传递,而extra = char * world。 如果你没有额外传递任何东西,##将丢弃逗号。
答案 2 :(得分:0)
简而言之:宏正在使用参数name
指定的名称和extra ...
指定的可选附加参数创建函数。
注意:以双下划线开头的名称是保留的实现,不应该使用。
宏是可变的。
宏extra ...
的第二个参数提供了一个名称,而不是函数声明宏中的默认__VA_ARGS__
。这是一个GNU扩展
## extra
是另一个GNU扩展,它向预处理器指定如果省略宏__COMMAND_HANDLER
的第二个参数,则可以删除前面的逗号并在没有它的情况下调用该函数。
您无法找到name
声明的原因是因为它是您宏的参数!宏本身正在声明一个新函数,其中包含名称和提供的参数,以及struct command_invocation *cmd
的默认第一个参数。
以下是一些例子:
调用:
__COMMAND_HANDLER(cmd,char * w)
会导致功能声明:
int cmd(struct command_invocation *cmd,char * w)
呼叫:
__COMMAND_HANDLER(cmd2)
会产生以下功能声明:
int cmd2(struct command_invocation *cmd)