在C中声明具有可变大小的全局结构变量

时间:2015-01-06 21:53:41

标签: c struct

我有一个看起来像这样的结构。

struct MyStruct1 {
    int (*fn)();
    int b;
}

另一个看起来像这样的结构。

struct MyStruct2 {
    int a;
    struct MyStruct1 b[0];
}

我想声明MyStruct2类型的全局变量,有点像这样。

int func1() { return 1; }
int func2() { return 2; }
struct MyStruct2 a = { 1, { func1, 5 }, { func2, 6 } };

但是,我得到一个“初始化元素不是编译时常量”。

我想知道(a)是否有可能全局声明一个可变大小的结构(或者至少定义一个空格块,大小正确,以便稍后插入值),以及(b)如果是的话,我做错了什么?

2 个答案:

答案 0 :(得分:0)

您无法合法地在C中创建大小为0的数组。在C99或C11中,您可以使用灵活的阵列成员'像这样:

struct MyStruct2 {
    int a;
    struct MyStruct1 b[];
};

但是具有灵活数组成员的结构只能通过动态内存分配来创建(其他形式的分配会为您提供一个大小为0的不可用的灵活数组)。

旧的'结构黑客'具有可变大小数组的结构的版本在结构中使用大小为1的数组。您可以使用大小为1的数组创建此类结构的全局版本。

但基本上,你正试图做语言禁止你做的事情,而且非常令人惊讶的是,你失败了。

您对此采取的措施取决于您的需求。全局变量本身就有些不受欢迎,所以有一个元素是"你应该试图避免这样做"。也就是说,规则也适用于文件范围(static)变量,并且这些变量有很多用途。

您可以使用显式指针代替数组,并对struct MyStruct2的主体及其struct MyStruct1成员数组进行单独分配。您可以放弃全局变量,并使用灵活的数组成员使用动态分配的结构。

struct MyStruct2 *ms2 = malloc(sizeof(*ms2) + N * sizeof(ms2->b[0]));

这会在数组中创建一个struct MyStruct2(如本答案顶部所示),其中包含N个成员。如果没有任何进一步的更改,您可以使用ms2->b[0]ms2->b[N-1](除了错误检查malloc()成功之外)。

答案 1 :(得分:0)

无法在本地或全局声明可变大小struct。每种类型都有一个在编译时确定的固定大小。

但是,您报告的错误消息令人惊讶。如果您提供的所有声明都在文件范围内,在同一文件中,按照您给出的顺序,那么变量a 的初始化程序是编译时常量。但是,它不是struct MyStruct2

的正确初始值设定项
  • 因为它指定的元素多于struct类型具有成员的元素,
  • 因为a.b的初始值设定项元素是struct MyStruct1的初始值设定项,而不是数组的初始值设定项,
  • 因为即使您将最后两个初始化元素转换为一个数组初始值设定项,它的元素也多于a.b中的元素(即大于零)。

如果你想要一个动态大小的数组,无论是作为一个变量本身还是作为struct的成员,那么你必须声明一个指向它的指针,并动态地为这些元素分配内存。在这种情况下,元素本身不是struct的一部分;只有指向它们的指针是。 (顺便说一句,这与固定大小的数组不同,后者的大小在其初始化程序中是隐式的;但这些数据仅适用于独立类型,不适用于structunion成员的类型。

修改 正如ShafikYaghmour评论的那样,C99柔性阵列是一种可能的替代方案。它们与struct元素类似但不相同,后者是指向动态分配数组的指针。但是,在这种情况下,您不仅无法静态声明数组元素,还无法静态声明struct本身的实例,因此这根本不会解决您的初始化程序问题。还有其他一些怪癖和限制。我个人认为灵活数组没有什么优势,但它们确实使得正确释放struct实例变得容易一些。