在 C 中使用
_Generic
和复合文字时,我遇到了意外的行为。看起来 _Generic
选择第一个包含复合文字的情况,无论它是否与表达式的实际类型匹配。即使其他情况应该更精确地匹配,也会发生这种情况。
考虑以下代码:
typedef struct { unsigned char _dummy_m[3]; } int24_t;
#define GET_VALUE_ADDRESS(v) _Generic((v), \
int*: &(v), \
double: &(double){v}, \
int24_t: &(v), \
default: &(v))
int main (void)
{
int24_t val = {1,2,3};
void* addr = GET_VALUE_ADDRESS(val); /* erroneous */
return 0;
}
编译器是 MinGW-GCC Rev2,由 MSYS2 项目 10.3.0 构建,并具有以下 CMake 配置:
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON)
代码产生以下错误:
incompatible types when initializing type 'double' using type 'int24_t'
预期行为:
在此示例中,
v
的类型为 int24_t
,因此我希望 _Generic
匹配 int24_t
大小写并返回 &(v)
。
实际行为:
相反,编译器似乎总是选择第一个涉及复合文字的情况(在本例中为
&(double){v}
),无论 v
的类型如何。这会导致类型匹配不正确和意外的输出。
附加信息:
如果我删除复合文字并将其替换为常规地址操作,则
_Generic
按预期工作。仅当使用复合文字作为 _Generic
中的返回值时,才会出现此问题。
问题: 即使这不是
_Generic
本身的错误或怪癖,我得到的错误仍然毫无帮助。
这是一个已知的错误还是 _Generic 如何处理复合文字的限制?如果是这样,是否有任何解决方法,或者我在这种情况下滥用了_Generic
?
看起来
选择了第一个包含复合文字的情况......_Generic
_Generic
此处未选择任何大小写,或者更准确地说,编译器尚未将 _Generic
表达式解析为任何操作数。
错误消息来自分析整个
_Generic
表达式,如下所述。
incompatible types when initializing type 'double' using type 'int24_t'
_Generic
不是预处理器构造。它是 C 语言中的一个表达式,并且其列表中的所有表达式都必须是真表达式(具体来说,每个表达式都必须是形式语法中的赋值表达式)。当v
为val
时,&(double){v}
为&(double){val}
。该表达式由编译器分析,其中的复合文字尝试使用 double
初始化 val
。 val
是一个 int24_t
,您已将其定义为结构体。编译器正确报告尝试使用结构初始化 double
的错误。
此列表项稍后不会被
_Generic
选择这一事实是无关紧要的;编译器必须首先全面分析每个列表项。此项目无法分析。
这是一个已知的错误还是
处理复合文字的限制?_Generic
不,这是编译器的正确行为,并且是源代码中的实际错误。
如果是这样,是否有任何解决方法,或者我在这种情况下滥用了
?_Generic
虽然你的两个标签是
double
和int24_t
,但我怀疑你想让它们成为double *
和int24_t *
。如果是这样,那么,在您将 _Generic
结果分配给 void *
的用例中,您可以简单地使用:
void *addr = &val;
或者,仅更改宏定义:
#define GET_VALUE_ADDRESS(v) &(v)
…
void *addr = GET_VALUE_ADDRESS(val);
如果这不能满足您的目的,您需要说明您的要求。