C 在编译时检查数组内容
C check array content at compile time
我有一个枚举和一个结构数组。结构中的第一个字段是枚举类型。现在我想在编译时检查第一个数组元素的第一个字段中的值是否与枚举类型的第一个值相同。与第二个元素相同,依此类推...
基本上是这样的:
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
但这不起作用,编译器说 "token "[“在预处理器表达式中无效”。
我也试过这样的东西:
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 来关闭它,但这样您就不会遇到编译时失败)而且我已经有一些误报。
我有一个枚举和一个结构数组。结构中的第一个字段是枚举类型。现在我想在编译时检查第一个数组元素的第一个字段中的值是否与枚举类型的第一个值相同。与第二个元素相同,依此类推...
基本上是这样的:
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
但这不起作用,编译器说 "token "[“在预处理器表达式中无效”。 我也试过这样的东西:
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 来关闭它,但这样您就不会遇到编译时失败)而且我已经有一些误报。