Note: this version of this answer is the result of a major rewrite. Some claims have been removed and others significantly modified, so as to focus on and better justify the most important points.
Variadic macros and their variable arguments
[Controversial, much disputed position removed. It was more distracting than helpful.]
The proposed macro
I think I've found an easy solution that is both compact and standard:
#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
We can sidestep any question of undefinedness by considering this variation:
#define is_empty(dummy, ...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
. The same considerations apply to the interpretation of empty vs. non-empty variable arguments here as do in your original version. Specifically,
Based on C17 6.10.3.2/2 (the # operator): "The character string
literal corresponding to an empty argument is """, I believe that
#__VA_ARGS__
is always well-defined.
I agree. Also relevant here is section 6.10.3.1/2: "An identifier __VA_ARGS__
that occurs in the replacement list shall be treated as if it were a parameter [...]."
Explanation of the macro:
- This creates a compound literal char array and initializes it by using a string literal.
Yes.
- No matter what is passed to the macro, all arguments will be translated to one long string literal.
Yes. __VA_ARGS__
is treated as a (one) parameter. If there are multiple variable arguments then that can impact the rescan, but the stringification operator has its effect at the point of the macro expansion, before rescanning.
- In case the macro list is empty, the string literal will become "", which consists only of a null terminator and therefore has size 1.
Yes.
- In all other cases, it will have a size greater than 1.
Yes. This holds even in the case of two zero-token arguments in the variable argument list, is_empty(dummy,,)
, where #__VA_ARGS__
will expand to ","
. It also holds in the case of an argument consisting of an empty string literal, is_empty(dummy, "")
, where #__VA_ARGS__
will expand to "\"\""
.
HOWEVER, that still might not serve your purpose. In particular, you cannot use it in a conditional compilation directive. Although sizeof
expressions are generally allowed in integer constant expressions, such as form the control expressions of such directives,
Therefore, if your macro is used as or in the control expression of a conditional compilation directive then it will be evaluated as if the sizeof
operator in it were replaced by 0
, yielding an invalid expression.