C宏_Generic产生了意外的编译器错误 [英] C macro _Generic gives unexpected compiler error
问题描述
使用gcc.exe(Rev3,由MSYS2项目构建)8.2.0.
Using gcc.exe (Rev3, Built by MSYS2 project) 8.2.0.
我试图建立一个宏来自动进行两种类型之间的类型转换,其中两个参数绝不能是同一类型.我的问题是,如果我也不包含相同类型的大小写,则编译器将引发错误.我想要的是:
I was trying to build a macro to automatically do type conversions between two types, where the two parameters should never be the same type. My problem is the compiler throws an error if I don't also include the same type case. What I wanted:
#include <stdio.h>
#include <stdint.h>
// Macro to return string based on two different types
#define bob( to, from ) \
_Generic( to , \
int32_t: _Generic(from, \
int16_t: "s-l", \
int8_t: "c-l" ) , \
int16_t: _Generic(from, \
int32_t: "l-s", \
int8_t: "c-s") , \
int8_t:_Generic(from, \
int32_t: "l-c", \
int16_t: "s-c") \
)
void main(void)
{
int32_t i1;
int16_t s1;
int8_t c1;
printf("%s\n", bob(i1,s1));
printf("%s\n", bob(i1,c1));
printf("%s\n", bob(s1,c1));
printf("%s\n", bob(s1,i1));
printf("%s\n", bob(c1,s1));
printf("%s\n", bob(c1,s1));
}
$ gcc gbug.c -o gbug.exe
gbug.c: In function 'main':
gbug.c:23:27: error: '_Generic' selector of type 'short int' is not compatible with any association
printf("%s\n", bob(i1,s1));
^~
gbug.c:9:19: note: in definition of macro 'bob'
int16_t: _Generic(from, \
^~~~
gbug.c:24:27: error: '_Generic' selector of type 'signed char' is not compatible with any association
printf("%s\n", bob(i1,c1));
^~
gbug.c:12:17: note: in definition of macro 'bob'
int8_t:_Generic(from, \
^~~~
gbug.c:25:27: error: '_Generic' selector of type 'signed char' is not compatible with any association
printf("%s\n", bob(s1,c1));
^~
gbug.c:12:17: note: in definition of macro 'bob'
int8_t:_Generic(from, \
^~~~
gbug.c:26:27: error: '_Generic' selector of type 'int' is not compatible with any association
printf("%s\n", bob(s1,i1));
^~
gbug.c:6:19: note: in definition of macro 'bob'
int32_t: _Generic(from, \
^~~~
gbug.c:27:27: error: '_Generic' selector of type 'short int' is not compatible with any association
printf("%s\n", bob(c1,s1));
^~
gbug.c:9:19: note: in definition of macro 'bob'
int16_t: _Generic(from, \
^~~~
gbug.c:28:27: error: '_Generic' selector of type 'short int' is not compatible with any association
printf("%s\n", bob(c1,s1));
^~
gbug.c:9:19: note: in definition of macro 'bob'
int16_t: _Generic(from, \
这个例子是我发现失败的最简单的例子.
This example is the simplest that I have found that will fail.
如果我这样添加相同类型"的转换行:
If I add in the "same type" conversion lines like this:
#define bob( to, from ) \
_Generic( to , \
int32_t: _Generic(from, \
int16_t: "s-l", \
int32_t: "bug", \
int8_t: "c-l" ) , \
int16_t: _Generic(from, \
int32_t: "l-s", \
int16_t: "bug", \
int8_t: "c-s") , \
int8_t:_Generic(from, \
int32_t: "l-c", \
int8_t: "bug", \
int16_t: "s-c") \
)
它可以生成并以预期的结果运行:
It build and runs with the expected result:
$ ./gbug.exe
s-l
c-l
c-s
l-s
s-c
s-c
验证我没有使用宏来扩展任何相同的类型条件.我了解_Generic不是字符串替换宏,但我也认为,如果您可以在没有默认情况下使用它,则在使用未知类型(或不支持的类型组合)时,它将正确引发编译错误,这是我想要的行为)就像预处理器将两个宏参数混合在一起.
verifying that I am not using the macro to expand any same type conditions. I understand _Generic is not a string substitution macro but I also thought that if you could use it without a default case it would correctly throw a compile error if you used an unknown type (or an unsupported combination of types, which is the behaviour I wanted) It is like the pre-processor is getting the two macro parameters mixed up.
所以我有一个更好的理解,(请参阅下面的答案),但是如果两个参数是同一类型,则仍希望获取该宏以引发编译错误.到目前为止,我有一个技巧来强制执行链接错误,该错误仍然比运行时错误好.
So I have a better understanding, (See my answer below) but still looking to get the macro to throw a compile error if the two parameters are the same type. So far I have a trick to force a link error which is still better than a runtime error.
推荐答案
问题在于,即使未评估泛型选择的每个分支,这些分支也必须有效.
The problem is that every branch of a generic selection must be valid, even if they are not evaluated.
例如,您的第一个宏:
bob(i1, s1)
扩展为(为清楚起见添加了类型):
Expands to (types added for clarity):
_Generic( ((int32_t) i1),
int32_t: _Generic( ((int16_t) s1),
int16_t: "s-l",
int8_t: "c-l" ),
int16_t: _Generic( ((int16_t) s1), // The error is here
int32_t: "l-s",
int8_t: "c-s"),
int8_t:_Generic( ((int16_t) s1),
int32_t: "l-c",
int16_t: "s-c")
)
显然, uint32_t
分支是有效的:它只是选择"s-l"
.但是 int16_t
分支无效有效,因为 from
( int16_t
本身)没有相应的分支.
Obviously the uint32_t
branch is valid: It just selects "s-l"
. But the int16_t
branch is not valid, as from
(An int16_t
itself) does not have a corresponding branch.
在这种特殊情况下,添加不执行任何操作的自转换运算符不会有什么坏处.
In this particular scenario, it wouldn't hurt to add a self-conversion operator that does nothing.
这篇关于C宏_Generic产生了意外的编译器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!