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

标签 c c-preprocessor c11 variadic-macros

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

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

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

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

基于C17 6.10.3.2/2(#运算符):“空参数对应的字符串字面量是”“,我认为#__VA_ARGS__ 始终定义明确。

宏的解释:

  • 这将创建一个复合文字 char 数组并使用字符串文字对其进行初始化。
  • 无论传递给宏的是什么,所有参数都将被翻译成一个长字符串文字。
  • 如果宏列表为空,则字符串文字将变为 "",它仅包含一个空终止符,因此大小为 1。
  • 在所有其他情况下,它将具有大于 1 的大小。

最佳答案

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

可变参数宏及其可变参数

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


提议的宏

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 节:“替换列表中出现的标识符 __VA_ARGS__ 应被视为参数 [...]。”

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__ 被视为一个(一个)参数。如果有多个可变参数,则可能会影响重新扫描,但字符串化运算符在重新扫描之前的宏扩展点会产生影响。

  • 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,产生无效的表达式。

关于c - 这是检查可变宏参数列表是否为空的有效方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55417186/

相关文章:

c - 从实模式切换到保护模式后远跳

c++ - C11 编译。翻译阶段 #1 和 #5。通用字符名称

c - C11中const限定符的性能优势

c++ - 生成整数对数常量数组的项值

C11 - 通用选择中的枚举

c++ - 与枚举的隐式转换

c - 为什么 itoa 被宣布为不安全?

c - 如何删除指定索引后的数组元素

ios - Objective-C - #define 使用 __VA_ARGS__

c - 如何将 argv[1] 用作预定义宏?