首页 > 解决方案 > 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];

但结果相同。如果可能的话,我如何实施这样的检查?

谢谢你。

标签: carrayscompile-time

解决方案


你不能。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 来关闭它,但是您不会遇到编译时失败)而且我有一些误报它。


推荐阅读