我是否可以使用gcc扩展在编译时强制执行显式初始化的数组大小?

我是否可以使用gcc扩展在编译时强制执行显式初始化的数组大小?,c,gcc,c99,C,Gcc,C99,如果某个显式初始化的C数组中的元素数不等于某个值,我可以强制GCC在编译时抛出警告或错误吗? 考虑以下简单的C程序: #include <stdio.h> enum my_enum { MY_ENUM_FIRST, MY_ENUM_SECOND, MY_ENUM_THIRD, MY_ENUM_COUNT }; // indexable by my_enum const char *my_enum_names[] = { "first",

如果某个显式初始化的C数组中的元素数不等于某个值,我可以强制GCC在编译时抛出警告或错误吗?

考虑以下简单的C程序:

#include <stdio.h>

enum my_enum {
    MY_ENUM_FIRST,
    MY_ENUM_SECOND,
    MY_ENUM_THIRD,
    MY_ENUM_COUNT
};

// indexable by my_enum
const char *my_enum_names[] = {
    "first",
    "second",
    "third",
};

int main(void) {
    int i;

    for (i = 0; i < MY_ENUM_COUNT; i++)
    {
        printf("%s\n", my_enum_names[i]);
    }
}
#包括
枚举我的枚举{
首先是我的枚举,
我的第二个,
我的第三个,
我的枚举数
};
//可由my_enum索引
常量字符*我的枚举名称[]={
“第一”,
“第二”,
“第三”,
};
内部主(空){
int i;
对于(i=0;i
除非它们在代码中直接相邻,否则开发人员可能不会意识到枚举和数组必须保持彼此“同步”。开发人员可能会向枚举中添加条目,但不会向数组中添加条目(反之亦然),因此会暴露越界漏洞

我是否可以在
我的枚举名称的定义中添加某种pragma或属性
,以便如果其大小不等于
我的枚举计数
,编译器将抛出警告或错误?

一些澄清:

  • 我特别指的是显式初始化的数组,这意味着它们的大小在编译时是已知的
  • 我指的是GCC编译器,包括编译器扩展
我发誓我以前做过这件事,可能是使用了GCC的一个
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu属性扩展,但现在我找不到任何符合我要求的功能的文档。

怎么样

const char *my_enum_names[MY_ENUM_COUNT] = { ... };
然后数组将始终包含足够的元素,但有些元素可能是
NULL
,您需要添加check来代替。这总比冒险越界要好

同样,在上面,如果您删除枚举,那么如果您忘记更新数组初始化,编译器将警告您有太多初始值设定项

_Static_assert(sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT,
    "my_enum_names is the wrong size.");
在将
\u Static\u assert
添加到该语言之前,您可以使用以下声明在这些情况下强制出错:

extern char my_enum_namesIsTheWrongSize[1];
extern char my_enum_namesIsTheWrongSize[sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT];

如果后者中的测试为false,它将尝试声明一个包含零元素的数组,这本身就是一个错误,但是,为了防止编译器不报告零大小的数组,它还与前面的声明冲突,因此,它应该会生成一条错误消息。

您正在查看GCC的
-Warray bounds
编译标志吗?奇怪的是,我很难从GCC中找到任何关于
\u Static\u assert
的真实官方文档。看起来,
static\u assert
是C11的一部分,glibc在
assert.h
中实现了它,gcc本身从4.6开始就支持
\u static\u assert
,但是我没有看到任何手册页,甚至没有描述函数的任何变体的参数和预期行为的文档。gcc/tcc/clang都接受零大小的数组,没有错误。您通常希望将bool-the-zero转换为负int,以使编译真正失败。@WoodrowBarlow:它不是GCC扩展。自2011年以来,它是标准C的一部分。