kimokono
kimokono

Reputation: 45

incomprehensible C macro

I bumped into the following macro while analyzing a code.

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

The function name is passed as an argument to __COMMAND_HANDLER however there is no definition of this function anywhere else in the code. The cmd argument's type (command_invocation) is defined. Basically I couldn't understand the functionality of this macro because I couldn't find the definition of the function name. Is name some kind of pre-defined function in standard C library ? Does this macro definition make sense if name is not defined ?

Upvotes: 2

Views: 176

Answers (3)

Akira
Akira

Reputation: 4473

Durning preprocession, the preprocessor will replace all occurrences of __COMMAND_HANDLER(name, extra ...) macro to its body with replacing each occurences of name and extra... inside its body to the tokens you specified.

This means in this case that whatever you enter for name argument, it will be a function name, and extra... will be its additional parameters beside the first one (struct command_invocation *cmd).

For example the following line:

__COMMAND_HANDLER(foo, int param) {
    /* definition */
}

after preprocessing will be:

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

One important thing has to be clarified: the ## before extra and named variable argument (using extra... instead of ...) are not the part of the standard but they are GNU extensions. The effect of ## after comma lets you specify nothing for variable argument. Compiling your example with GCC (with -pedantic flag) when it's used as follows, you will see warning messages:

/* 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);

Normally the ## is the operator for token concatenation, i.e. two tokens on either side of a ## operator are combined into a single one. For example:

#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;
}

Upvotes: 1

Johnathan Jacobs
Johnathan Jacobs

Reputation: 46

In short: the macro is creating the function with the name specified by the parameter name and optional additional arguments specified by extra ....

Note: names starting with a double underscore is implementation reserved and shouldn't be used.

The macro is variadic.

The second argument to the macro extra ... provides a name to use instead of the default __VA_ARGS__ inside the function declaration macro. This is a GNU extension

## extra is another GNU extension that specifies to the preprocessor that if the second argument to the macro __COMMAND_HANDLER is omitted, the preceding comma can be removed and the function called without it.

The reason you can't find the declaration of name is because it's a parameter to your macro! The macro itself is declaring a new function with whatever is in name, and the arguments provided, with the default first argument of struct command_invocation *cmd.

Here are some examples:

Calling:
__COMMAND_HANDLER(cmd,char * w)
Would result in the function declaration of:
int cmd(struct command_invocation *cmd,char * w)

Whereas calling:
__COMMAND_HANDLER(cmd2)
would result in the function declaration of:
int cmd2(struct command_invocation *cmd)

Upvotes: 0

Daniel Tran
Daniel Tran

Reputation: 6171

This is a macro and name is a parameter. You use it like this:

__COMMAND_HANDLER(hello, char* world)

During pre-process stage, it would transform your code into:

int hello(struct command_invocation *cmd, char *world);

In this case, name is passed as hello, and extra = char* world. If you don't pass anything for extra, ## will discard the comma.

Upvotes: 0

Related Questions