将复合文字传递给_Generic无效
在以下代码中:将复合文字传递给_Generic无效,c,C,在以下代码中: struct Person { char* name; int age; }; struct Book { char* title; char* author; }; #define MYTYPE(X) _Generic((X), int: "int", float: "float", double: "double", struct Book: "book",
struct Person {
char* name;
int age;
};
struct Book {
char* title;
char* author;
};
#define MYTYPE(X) _Generic((X), int: "int", float: "float", double: "double", struct Book: "book", struct Person: "person", default: "other")
以下工作:
struct Book ulysses = {"ulysses", "james"};
printf("%s\n", MYTYPE(ulysses));
struct Person jim;
jim = (struct Person) {"Tom", 20};
printf("%s\n", MYTYPE(jim));
但是,如果我尝试传递复合文字,它将失败:
printf("%s\n", MYTYPE((struct Person){"Tom", 10}));
gen.c:25:53:错误:宏“MYTYPE”传递了2个参数,但只接受1个printf(“%s\n”,MYTYPE((struct Person){“Tom”,10}))
............................................................................... ^ 将
struct Person
传递到MYTYPE
宏时出现了什么问题
更新:在parens中双重包装表达式似乎可以解决这个问题,但我不确定为什么需要这样做:
printf("%s\n", MYTYPE(((struct Person){"Tom", 10})));
typedef结构人{
字符*名称;
智力年龄;
}t_Person;//(对不起,我养成了这个习惯)
请注意,如果您声明它,则不再需要对其进行双重包装:
t_Person a={“Tom”,10};
printf(“%s\n”,MYTYPE(((t_Person){“Tom”,10}));->作品
printf(“%s\n”,MYTYPE(a));->有效,保存4个括号。
我的猜测是MYTYPE不知道自己的内部是什么,因为它可能是int、float等。。。因此编译器认为括号之间的结构实际上是一个强制转换,而不是一个声明,添加另一个括号可以解决冲突
我可以用以下几点来证明:
#定义MYTYPE(X)(X)、char:“char”、int:“int”、float:“float”、double:“double”、struct Book:“Book”、struct Person:“Person”、default:“other”)
printf(“%s\n”,MYTYPE((int){'a'}));//->输出整数
printf(“%s\n”,MYTYPE((char){'a'}));//->输出字符
。转换仅在类型域中执行:它丢弃顶级cvr限定符和原子性,并将数组到指针/函数到指针转换应用于控制表达式的类型,而不会引发任何副作用或计算任何值
您遇到的问题是由于预处理器语法造成的
MACRONAME(a,b)
意味着使用两个参数a
和b
调用MACRONAME,而不管a
、逗号和b
的组合是否恰好形成了语义上有效的表达式。(在预处理阶段,我们还没有将标记排列成表达式)
例外情况与字符串文字和匹配的括号对有关:
- 字符串文字中的逗号不是参数分隔符
- 匹配的一对括号内的逗号不是分隔符。(这指的是参数列表中的括号,而不是宏替换语法中的括号)
因此,双括号起作用的原因是:
MACRONAME((a,b))
意味着用一个参数(a,b)
调用MACRONAME
,您用两个参数调用了MYTYPE
:(struct Person){“Tom code>和10}
。与括号不同,大括号在预处理器级别上没有语法意义,并且不禁止逗号作为宏参数分隔符的作用。您需要在复合文本中加括号以避免这种情况。或者,在某些情况下(包括您的情况),您可以使用..
和\uu VA\u ARGS\uuu
生成一个可避免问题的可变宏。另请参见我的问题:@chux:是的,这是有效的,但我很好奇,如果我已经在函数调用中,为什么需要这个部分()
Hmmmm………什么编译器和版本?@Shawn gcc 7.5.0(在c代码中执行\uu version\uuuu
,这就是你的意思吗?)使用较新的gcc版本(和clang)在门闩上?可能是一个编译器错误,希望已经修复。为了澄清这一点,OP的宏调用有两个参数:(struct Person){“Tom”
和10}
@M.M。请您解释一下匹配括号内的逗号如何不是分隔符。
有效吗?这是否意味着除了函数调用本身之外还有一个括号?所以…函数((a,b))
而不是函数(a,b)
?@carl.hiass是的,我在最后一段中给出了这个例子。此外,这些不是函数调用,而是宏替换MACRONAME(参数列表)
是宏替换调用的语法。这些括号不是论点列表的一部分,这是一个很好的解释。你能解释一下..
是如何解决这个问题的另一种方法吗?@carl.hiass:如果宏只接受一个变量..
参数,\uu VA\u ARGS\uuu
将扩展到由逗号分隔的整个参数集,因此它将“重新组合”一个拆分为多个参数的复合文字。我忘了在没有非变量参数的情况下使用…
在技术上是否是有效的C语言,但我所知道的所有编译器都支持它,我认为是的。