Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect presence or absence of arguments in a C macro

How can one define a C macro IFARGS(YES, NO, ...) such that invoking IFARGS with no additional arguments produces NO, and invoking IFARGS with one or more arguments produces YES?

I have an answer using GCC (see below), but I'd prefer one for C99 if possible (or a proof of its impossibility).

like image 861
augurar Avatar asked Jan 31 '14 06:01

augurar


People also ask

Which arguments are associated with a macro?

The macro definition can include macro arguments, which can be assigned specific values in the macro call. There are two types of arguments: keyword and positional. Keyword arguments are assigned names in the macro definition; in the macro call, they are identified by name.

What is macro explain macro with arguments?

macro (array[x = y, x + 1]) passes two arguments to macro : array[x = y and x + 1] . If you want to supply array[x = y, x + 1] as an argument, you can write it as array[(x = y, x + 1)] , which is equivalent C code. All arguments to a macro are completely macro-expanded before they are substituted into the macro body.

How many arguments macro can have in C?

For portability, you should not have more than 31 parameters for a macro. The parameter list may end with an ellipsis (…). In this case, the identifier __VA_ARGS__ may appear in the replacement list.

Can you supply more than one argument in a macro call?

It is possible to supply more than one p pp y argument in a macro call. Each argument must correspond to a definition(“dummy”) argument on the macro name line of the argument on the macro name line of the macro definition.


2 Answers

In C99 it is possible to detect if a macro argument is empty, but making that robust against all odds that may appear in that argument (arguments that are themselves expanding, contain () and stuff like that) is difficult. My macro package P99 implements such a thing, so you wouldn't have to worry too much. With that your macro can be implemented as

#define IFARGS(YES, NO, ...) P99_IF_EMPTY(__VA_ARGS__)(YES(__VA__ARGS__))(NO())

As its name indicates, P99 is only building on C99 features for that.

like image 132
Jens Gustedt Avatar answered Oct 19 '22 17:10

Jens Gustedt


#define GET(_0, _1) _0  // Return the first of two arguments
#define GET_(_0, _1) _1  // Return the second of two arguments

#define JOIN(_0, _1) _0 ## _1  // Concatenate two arguments
#define EJOIN(_0, _1) JOIN(_0, _1)  // Expand macros and concatenate

#define FIRST(_, ...) _  // Truncate everything after first comma
#define EFIRST(_) FIRST(_)  // Expand argument and pass to FIRST

#define REST(_0, ...) __VA_ARGS__  // Remove everything before first comma

#define GET_GET(...) \
    EJOIN(GET, EFIRST(REST(,,##__VA_ARGS__ _)))  // Branch between GET and GET_

#define IFARGS(YES, NO, ...) GET_GET(__VA_ARGS__)(YES, NO)

Note that if this were possible in C99, then it would be possible to simulate ##__VA_ARGS__, like so:

#define PREPEND_COMMA(...) , __VA_ARGS__
#define NO_COMMA()
#define PREPEND_COMMA_IF_NONEMPTY(...) IFARGS(PREPEND_COMMA, NO_COMMA, __VA_ARGS__)(__VA_ARGS__)

Then any instance of , ##__VA_ARGS__ could be replaced by PREPEND_COMMA_IF_NONEMPTY(__VA_ARGS__).

like image 26
augurar Avatar answered Oct 19 '22 19:10

augurar