c - C 在编译时检查数组内容
问题描述
我有一个枚举和一个结构数组。结构中的第一个字段是枚举类型。现在我想在编译时检查第一个数组元素的第一个字段中的值是否与枚举类型的第一个值相同。与第二个元素相同,依此类推...
基本上是这样的:
typedef enum {
A = 0,
B,
C
} enumerator1;
typedef struct {
enumerator1 a;
unsigned char foo;
unsigned char bar;
} structure1;
const structure1 array1[3] =
{
{A, 1, 1}, //This element should contain A
{C, 1, 1}, //This element should contain B
{B, 1, 1} //This element should contain C
};
在上面的示例中,B 和 C 交换了,我想在编译时捕获它。我正在寻找的是这样的:
#if array1[0].a != A
#error
#endif
但这不起作用,编译器说“令牌“[”在预处理器表达式中无效”。我也尝试过这样的事情:
typedef unsigned char Check[(array1[0].a != A) ? 1 : -1];
但结果相同。如果可能的话,我如何实施这样的检查?
谢谢你。
解决方案
你不能。C 中的数组在概念上是运行时的东西。没有可移植的方法来强制对此进行 comptime 断言。
这并不意味着优化编译器不会看到它。
如果我这样做if(!(array1[0].a == A)) abort();
并查看反汇编,我可以看到当我在优化的情况下编译时 gcc 和 clang 都完全省略了这段代码。
有一个 GCC 技巧可以让您将这种优化器知识转化为 comptime 断言(或者我称之为 ASAP 断言)。
#if __GNUC__ && !__clang__
#pragma GCC diagnostic error "-Walloc-size-larger-than=999999999L"
#endif
#if NDEBUG
enum { ndebug=1};
#else
enum { ndebug=0};
#endif
#include <assert.h>
#define ASAP_ASSERT(X) \
do{ \
/*if possible, statically assert it even without the optimizer*/ \
(void)(__builtin_constant_p(X) ? sizeof(int[(X)?1:-1]) : 0); \
_Bool ASAP_ASSERT=(X); /*prevent double evaluation*/ \
if(!ndebug){ \
/*try to make the optimizer raise a -Walloc-size-larger-than=*/ \
_Bool volatile ASAP_ASSERT__[(ASAP_ASSERT)?1:-1]; \
ASAP_ASSERT__[0]=0; \
(void)ASAP_ASSERT__; \
} \
assert(ASAP_ASSERT); /*if all static assert attempts fail, do it dynamically*/ \
}while(0)
typedef enum {
A = 0,
B,
C
} enumerator1;
typedef struct {
enumerator1 a;
unsigned char foo;
unsigned char bar;
} structure1;
const structure1 array1[3] =
{
{A, 1, 1}, //This element should contain A
{C, 1, 1}, //This element should contain B
{B, 1, 1} //This element should contain C
};
#include <stdlib.h>
int main()
{
ASAP_ASSERT(array1[0].a!=A); //will cause a comptime failure on gcc when compiled with at least -O1
}
缺点是它是 GCC 特定的,运行时成本很小(易失性写入,您可以通过将 ndebug 设置为 1 来关闭它,但是您不会遇到编译时失败)而且我有一些误报它。
推荐阅读
- ios - 快速合并 2 个视频并排二重奏视频
- c# - 在实体框架中使用三元条件运算符或表达式
- c# - 如何使用 .net 核心连接到 Cloud Firestore DB?
- python - 如何安装最新版本的seaborn
- kivy - 是否可以在 kivy 应用程序中禁用 GPU?
- python - regionprops 的 mean_intensity 属性根据 threshold_local 方法中指定的 block_size 返回不同的值
- google-maps - 如何在谷歌地图 Ionic 3 上删除多边形
- matlab - 如何在 Matlab 2018 断点后继续执行?
- vaadin - HasUrlParameter#setParameter 中的 Vaadin Flow 重新路由不会更改 URL?
- javascript - 未捕获的类型错误:无法读取 React 中未定义的属性“名称”