我一直在寻找一种方法来检查可变参数宏参数列表是否为空。我发现所有解决方案似乎都非常复杂,或者使用了非标准扩展。
我想我已经找到了既紧凑又标准的简单解决方案:
#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
问:在任何情况下,我的解决方案都会失败或调用定义不明确的行为?
基于C17 6.10.3.2/2(#运算符):“与空参数相对应的字符串文字是""
” ,我相信#__VA_ARGS__
总是定义明确的。
宏的说明:
""
,它仅包含一个空终止符,因此大小为1。答案 0 :(得分:2)
注意:此版本的答案是重大重写的结果。一些主张已被删除,而其他主张则进行了重大修改,以便专注于并更好地证明最重要的观点。
[有争议的位置被删除。分散注意力而不是有所帮助。]
我想我已经找到了既紧凑又标准的简单解决方案:
#define is_empty(...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
通过考虑这种变化,我们可以回避任何不确定性问题:
#define is_empty(dummy, ...) ( sizeof( (char[]){#__VA_ARGS__} ) == 1 )
。同样的注意事项也适用于解释空的 vs。非空变量参数。具体来说,
基于C17 6.10.3.2/2(#运算符):“ 字符串 与空参数相对应的文字是“” ”,我相信
#__VA_ARGS__
始终是明确定义的。
我同意。与此相关的还有第6.10.3.1/2节:“替换列表中出现的标识符__VA_ARGS__
应该被视为参数[...]。”
宏的说明:
- 这将创建一个复合文字char数组,并使用字符串文字对其进行初始化。
是的
- 无论传递给宏什么,所有参数都将转换为一个长字符串文字。
是的。 __VA_ARGS__
被视为 a (一个)参数。如果有多个变量参数,则可能会影响重新扫描,但是在重新扫描之前,字符串化运算符会在宏扩展时起作用。
- 如果宏列表为空,则字符串文字将变为“”,它仅包含一个空终止符,因此大小为1。
是的
- 在所有其他情况下,其大小都将大于1。
是的。即使在变量自变量列表is_empty(dummy,,)
中有两个零令牌自变量的情况下,这也适用,其中#__VA_ARGS__
将扩展为","
。在由空字符串文字is_empty(dummy, "")
组成的参数的情况下,它也成立,其中#__VA_ARGS__
将扩展为"\"\""
。
如何,可能仍然无法满足您的目的。特别是,您不能在条件编译指令中使用它。尽管sizeof
表达式通常在整型常量表达式中是允许使用的,例如整数形式的指令的控制表达式,
sizeof
作为预处理令牌被分类为标识符(预处理令牌的关键字和标识符之间没有区别),并且根据标准的paragraph 6.10.1/4,在处理条件编译指令的控制表达式时,
由于宏扩展和已定义的一元运算符而执行了所有替换之后,所有剩余的标识符(包括在词法上与关键字相同的标识符)都被替换为pp-number 0
(添加了重点)。
因此,如果将您的宏用作条件编译指令的控制表达式或在其中使用,则将其评估为好像其中的sizeof
运算符被0
替换,产生了无效的表达式
答案 1 :(得分:1)
我个人不喜欢混合宏/预处理器级别的评估和编译级别的测试。
似乎没有在宏级别执行此操作的标准方法,但是此处存在一些hacks: C++ preprocessor __VA_ARGS__ number of arguments