这是检查可变宏参数列表是否为空的有效方法吗?

Is this a valid way of checking if a variadic macro argument list is empty?

我一直在寻找一种方法来检查可变宏参数列表是否为空。我发现的所有解决方案似乎都非常复杂或使用非标准扩展。

我想我找到了一个既紧凑又标准的简单解决方案:

#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )

问:在某些情况下我的解决方案会失败或调用定义不明确的行为吗?

基于 C17 6.10.3.2/2(# 运算符):"The character string literal corresponding to an empty argument is """,我相信 #__VA_ARGS__ 始终是明确定义的。

宏的解释:

就我个人而言,我不喜欢混合使用 macro/preprocessor-level 评估和编译级测试。

在宏观层面似乎没有标准的方法来做到这一点,但这里存在黑客: C++ preprocessor __VA_ARGS__ number of arguments

注意:此答案的这个版本是重大重写的结果。一些声明已被删除,而另一些则进行了重大修改,以便专注于并更好地证明最重要的观点。

可变参数宏及其可变参数

[有争议的,有争议的立场已删除。它比帮助更让人分心。]


提议的宏

I think I've found an easy solution that is both compact and standard:

#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )

我们可以通过考虑这种变化来回避任何不确定性问题:

#define is_empty(dummy, ...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )

。同样的考虑适用于空 非空变量参​​数的解释,就像在你的原始版本中一样。具体来说,

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.

我同意。此处也相关的是第 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.

是的。

  • No matter what is passed to the macro, all arguments will be translated to one long string literal.

是的。 __VA_ARGS__ 被视为 a (一个)参数。如果有多个可变参数,则可能会影响重新扫描,但字符串化运算符会在重新扫描之前的宏扩展点产生影响。

  • In case the macro list is empty, the string literal will become "", which consists only of a null terminator and therefore has size 1.

是的。

  • In all other cases, it will have a size greater than 1.

是的。即使在变量参数列表 is_empty(dummy,,) 中有两个零标记参数的情况下也是如此,其中 #__VA_ARGS__ 将扩展为 ","。它也适用于由空字符串文字 is_empty(dummy, "") 组成的参数,其中 #__VA_ARGS__ 将扩展为 "\"\"".

然而,这可能仍然无法满足您的目的。特别是,您不能在条件编译指令中使用它。尽管 sizeof 表达式 通常 允许出现在整型常量表达式中,例如形成此类指令的控制表达式,

  • 词法上,作为预处理记号,sizeof归类为标识符(预处理记号不区分关键字和标识符),
  • 根据标准paragraph 6.10.1/4,在处理条件编译指令的控制表达式时,

    After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0

    (强调已添加)。

因此,如果您的宏被用作或用于条件编译指令的控制表达式,那么它将被计算为好像其中的 sizeof 运算符被 0 替换,产生无效的表达式。