难以理解的C宏

时间:2017-09-08 03:11:18

标签: c macros

我在分析代码时碰到了下面的宏。

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

函数name作为参数传递给__COMMAND_HANDLER但是代码中的其他任何地方都没有定义此函数。定义了cmd参数的类型(command_invocation)。基本上我无法理解这个宏的功能,因为我找不到函数name的定义。名称是标准C库中的某种预定义函数吗?如果未定义name,此宏定义是否有意义?

3 个答案:

答案 0 :(得分:1)

Durning预处理,预处理器将所有出现的__COMMAND_HANDLER(name, extra ...)宏替换为其主体,并将其身体内nameextra...的每个出现替换为您指定的标记。

这意味着在这种情况下,无论您为name参数输入什么,它都将是一个函数名称,extra...将是第一个参数旁边的附加参数(struct command_invocation *cmd)。

例如以下一行:

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

将是:

int foo(struct command_invocation *cmd, int param) {
    /* definition */
}

必须澄清一件重要的事情:##之前的extra和命名变量参数(使用extra...而不是...)不是{{##的一部分3}}标准,但它们是。逗号后-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)

相关问题