不可理解的C宏

不可理解的C宏,c,macros,C,Macros,我在分析代码时遇到了以下宏 #define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra) 函数名称作为参数传递给\uuu命令\u处理程序,但是在代码的其他地方没有此函数的定义。cmd参数的类型(命令调用)已定义。基本上我无法理解这个宏的功能,因为我找不到函数的定义name。name是标准C库中的某种预定义函数吗?如果未定义name,此宏定义有意义吗 这是一个宏,名称是一

我在分析代码时遇到了以下宏

#define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra)

函数
名称
作为参数传递给
\uuu命令\u处理程序
,但是在代码的其他地方没有此函数的定义。cmd参数的类型(
命令调用
)已定义。基本上我无法理解这个宏的功能,因为我找不到函数的定义
name
。name是标准C库中的某种预定义函数吗?如果未定义
name
,此宏定义有意义吗

这是一个宏,名称是一个参数。 您可以这样使用它:

__COMMAND_HANDLER(hello, char* world)
在预处理阶段,它会将您的代码转换为:

int hello(struct command_invocation *cmd, char *world);
在本例中,名称作为hello传递,extra=char*world。
如果没有传递任何额外的内容,则##将丢弃逗号。

在预处理过程中,预处理器将替换所有出现的
\u命令\u处理程序(name,extra…
宏到其主体,并将其主体中出现的
name
extra…
替换为指定的标记

这意味着在这种情况下,无论您为
name
参数输入什么,它都将是一个函数名,
extra…
将是它在第一个参数旁边的附加参数(
structcommand\u invocation*cmd

例如,以下行:

__COMMAND_HANDLER(foo, int param) {
    /* definition */
}
预处理后将:

int foo(struct command_invocation *cmd, int param) {
    /* definition */
}
必须澄清一件重要的事情:在
extra
之前的
#
和命名变量参数(使用
extra…
而不是
)不是标准的一部分,但它们是标准的一部分。逗号后的
##
的效果使您可以不为变量参数指定任何内容。使用GCC(带有
-pedantic
标志)编译示例,当按如下方式使用时,您将看到警告消息:

/* 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;
}
#包括
#定义FOO(名称、编号)无效名称##编号()
FOO(bar,1){puts(“我是第一名”);}
FOO(bar,2){puts(“我是第二名”);}
int main(){
bar1();
bar2();
返回0;
}

简而言之:宏正在使用参数
name
指定的名称和
extra…
指定的可选附加参数创建函数

注意:以双下划线开头的名称是保留的,不应使用

宏是可变的

extra…
的第二个参数提供了要使用的名称,而不是函数声明宏中的默认值
\uva\u ARGS\uuu
。这是一个GNU扩展

##extra
是另一个GNU扩展,它向预处理器指定,如果省略了宏
uu命令u处理程序
的第二个参数,则可以删除前面的逗号,并在不使用它的情况下调用函数

找不到
name
声明的原因是它是宏的一个参数!宏本身正在声明一个新函数,其名称和提供的参数都是默认的第一个参数
struct command\u invocation*cmd

以下是一些例子:

呼叫:
\u命令\u处理程序(cmd,char*w)

将导致函数声明:
int cmd(结构命令调用*cmd,char*w)

鉴于呼叫:
\u命令处理程序(cmd2)

将导致函数声明:

int-cmd2(struct-command\u-invocation*cmd)

注意宏定义不是标准的C;它正在使用GNU扩展。如果是标准宏,在三个点之前会有一个逗号。此外,以双下划线(或下划线和大写字母)开头的名称保留供“实现”使用。您不应该在自己的代码中定义这样的宏。请详细说明
..
组合使用的效果。