我可以在编译时使用 gcc 扩展强制执行显式初始化的数组大小吗?
Can I enforce explicitly-initialized array size at compile-time with gcc extensions?
如果某个显式初始化的 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]);
}
}
除非它们在代码中直接相邻,否则开发人员可能不会意识到枚举和数组必须彼此保持 "synchronized"。开发人员可以将条目添加到枚举而不是数组(反之亦然),因此会暴露越界漏洞。
我能否在 my_enum_names
的定义中添加某种编译指示或属性,以便如果其大小不等于 MY_ENUM_COUNT
,编译器将抛出警告或错误?
一些说明:
- 我指的是明确初始化的数组,这意味着它们的大小在编译时已知。
- 我特指 GCC 编译器,包括编译器扩展。
我发誓我以前做过这件事,可能是使用 GCC 的 __attribute__
扩展之一,但现在我找不到任何关于任何功能的文档来满足我的需求。
怎么样
const char *my_enum_names[MY_ENUM_COUNT] = { ... };
然后数组将始终包含足够的元素,但有些元素可能 NULL
然后您需要添加检查。总比冒险出界好。
另外,对于上面的内容,如果您删除了枚举,那么如果您忘记更新数组初始化,编译器将警告您关于许多初始化程序。
_Static_assert(sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT,
"my_enum_names is the wrong size.");
在将 _Static_assert
添加到该语言之前,您可以在这些情况下使用以下声明来强制出错:
extern char my_enum_namesIsTheWrongSize[1];
extern char my_enum_namesIsTheWrongSize[sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT];
如果后者的测试为假,它会尝试声明一个元素为零的数组,这本身就是一个错误,但是,以防万一编译器不报告大小为零的数组,也会与前面的声明,因此它应该生成一条错误消息。
如果某个显式初始化的 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]);
}
}
除非它们在代码中直接相邻,否则开发人员可能不会意识到枚举和数组必须彼此保持 "synchronized"。开发人员可以将条目添加到枚举而不是数组(反之亦然),因此会暴露越界漏洞。
我能否在 my_enum_names
的定义中添加某种编译指示或属性,以便如果其大小不等于 MY_ENUM_COUNT
,编译器将抛出警告或错误?
一些说明:
- 我指的是明确初始化的数组,这意味着它们的大小在编译时已知。
- 我特指 GCC 编译器,包括编译器扩展。
我发誓我以前做过这件事,可能是使用 GCC 的 __attribute__
扩展之一,但现在我找不到任何关于任何功能的文档来满足我的需求。
怎么样
const char *my_enum_names[MY_ENUM_COUNT] = { ... };
然后数组将始终包含足够的元素,但有些元素可能 NULL
然后您需要添加检查。总比冒险出界好。
另外,对于上面的内容,如果您删除了枚举,那么如果您忘记更新数组初始化,编译器将警告您关于许多初始化程序。
_Static_assert(sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT,
"my_enum_names is the wrong size.");
在将 _Static_assert
添加到该语言之前,您可以在这些情况下使用以下声明来强制出错:
extern char my_enum_namesIsTheWrongSize[1];
extern char my_enum_namesIsTheWrongSize[sizeof my_enum_names / sizeof *my_enum_names == MY_ENUM_COUNT];
如果后者的测试为假,它会尝试声明一个元素为零的数组,这本身就是一个错误,但是,以防万一编译器不报告大小为零的数组,也会与前面的声明,因此它应该生成一条错误消息。