c - 可以在 gcc _Static_assert 中使用 c11 的“通用”关键字吗
问题描述
我了解将 C11 的“通用”用于什么用途,并且我想在静态断言中使用它来保证两个用户定义的类型(typedef)是相同的原始类型。
我制作了一个宏,将每个原始类型映射到一个枚举值,并验证它是否按预期工作。但是,当我尝试在静态断言中比较来自两种类型的两个结果宏的相等性时,会出现编译器错误。当您注释掉静态断言时,代码会按预期工作。
在评估泛型扩展之前,编译器似乎正在评估静态断言。会是这样吗?我可以去哪里验证这个行为?
示例代码:
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
typedef enum
{
UTIL_TYPE_ENUM_BOOL,
UTIL_TYPE_ENUM_CHAR,
UTIL_TYPE_ENUM_SCHAR,
UTIL_TYPE_ENUM_UCHAR,
UTIL_TYPE_ENUM_SHORT,
UTIL_TYPE_ENUM_USHORT,
UTIL_TYPE_ENUM_INT,
UTIL_TYPE_ENUM_UINT,
UTIL_TYPE_ENUM_LONG,
UTIL_TYPE_ENUM_ULONG,
UTIL_TYPE_ENUM_LONG_LONG,
UTIL_TYPE_ENUM_ULONG_LONG,
UTIL_TYPE_ENUM_FLOAT,
UTIL_TYPE_ENUM_DOUBLE,
UTIL_TYPE_ENUM_LONG_DOUBLE,
UTIL_TYPE_ENUM_OTHER,
} UtilTypeEnum_t;
// returns the enumerated value representing a primitive type
#define UTIL_TYPE_GET_TYPE_ENUM(x) _Generic((x), \
_Bool: UTIL_TYPE_ENUM_BOOL, \
char: UTIL_TYPE_ENUM_CHAR, \
signed char: UTIL_TYPE_ENUM_SCHAR, \
unsigned char: UTIL_TYPE_ENUM_UCHAR, \
short int: UTIL_TYPE_ENUM_SHORT, \
unsigned short int: UTIL_TYPE_ENUM_USHORT, \
int: UTIL_TYPE_ENUM_INT, \
unsigned int: UTIL_TYPE_ENUM_UINT, \
long int: UTIL_TYPE_ENUM_LONG, \
unsigned long int: UTIL_TYPE_ENUM_ULONG, \
long long int: UTIL_TYPE_ENUM_LONG_LONG, \
unsigned long long int: UTIL_TYPE_ENUM_ULONG_LONG, \
float: UTIL_TYPE_ENUM_FLOAT, \
double: UTIL_TYPE_ENUM_DOUBLE, \
long double: UTIL_TYPE_ENUM_LONG_DOUBLE, \
default: UTIL_TYPE_ENUM_OTHER)
typedef int32_t foo_t;
typedef float bar_t;
// IF YOU COMMENT OUT THE STATIC ASSERT, THE CODE WILL COMPILE AND WORKS AS EXPECTED
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
int main(void)
{
foo_t foo;
bar_t bar;
printf("foo's type = %d\n", UTIL_TYPE_GET_TYPE_ENUM(foo));
printf("bar's type = %d\n", UTIL_TYPE_GET_TYPE_ENUM(bar));
if (UTIL_TYPE_GET_TYPE_ENUM(foo) != UTIL_TYPE_GET_TYPE_ENUM(bar))
{
printf("Not the same type!\n");
}
else
{
printf("Same type!\n");
}
return 0;
}
#endif
编译器错误:
$ gcc foo.c
foo.c:35:49: error: expected expression before ‘,’ token
#define UTIL_TYPE_GET_TYPE_ENUM(x) _Generic((x), \
^
foo.c:77:17: note: in expansion of macro ‘UTIL_TYPE_GET_TYPE_ENUM’
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
^~~~~~~~~~~~~~~~~~~~~~~
foo.c:35:49: error: expected expression before ‘,’ token
#define UTIL_TYPE_GET_TYPE_ENUM(x) (_Generic((x), \
^
foo.c:77:49: note: in expansion of macro ‘UTIL_TYPE_GET_TYPE_ENUM’
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
^~~~~~~~~~~~~~~~~~~~~~~
foo.c:77:16: error: expression in static assertion is not an integer
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
解决方案
选择的参数_Generic
必须是有效的 C 表达式,然后检查其类型。您提供一个类型名称,它根本不是一个表达式。
要获得您所追求的类型的表达式,您可以使用复合文字:
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM((foo_t){0})==UTIL_TYPE_GET_TYPE_ENUM((bar_t){0})),"ERROR");
(foo_t){0}
并且(bar_t){0}
现在是您要比较的类型的表达式,因此可以在通用选择中使用。
推荐阅读
- angular - ./node_modules/ng2-charts/fesm5/ng2-charts.js 中的警告 230:54-72 “在 '@angular/core' 中找不到导出 'ɵɵdefineInjectable'
- python - 根据特定条件将数据帧一列中的所有行转置为多列
- c# - 脚本任务错误:系统存储不足。服务器响应是:4.5.3。收件人过多 (AS780090)
- hive - 我们如何使用 URL 将数据加载到配置单元中
- struct - 如何在 Julia 中创建结构?
- android - 活动的 Edittext 自动填充覆盖在片段上可见
- java - Googlemaps V2:在 GeoJsonPolygon 上添加信息窗口
- microsoft-graph-api - 通过 Graph API 访问和创建团队聊天
- reactjs - react-setState 不清除文本框
- arrays - “() => x”类型中缺少属性“x”,但在“x”类型中是必需的