简体   繁体   English

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

[英]Declare Global Struct Variable With Variable Size In C

I have a struct that looks like this. 我有一个看起来像这样的结构。

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

And another struct that looks like this. 另一个看起来像这样的结构。

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

I would like to declare a global variable of type MyStruct2, somewhat like this. 我想声明一个MyStruct2类型的全局变量,有点像这样。

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

However, I get a "Initializer Element is not a compile-time constant". 但是,我得到一个“初始化器元素不是编译时常量”。

I would like to know (a) if it is even possible to globally declare a variable sized struct (or at least define a chunk of space, of the correct size, to have the values inserted into later), and (b) if it is, what am I doing wrong? 我想知道(a)是否有可能全局声明一个可变大小的结构(或至少定义一个大小正确的空间块,以便稍后再插入值),以及(b)是否是,我在做什么错?

You cannot create arrays of size 0 in C legitimately. 您不能合法地在C中创建大小为0的数组。 In C99 or C11, you can use a 'flexible array member' like this: 在C99或C11中,您可以使用“弹性数组成员”,如下所示:

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

but structures that have a flexible array member can only usefully be created with dynamic memory allocation (other forms of allocation give you an unusable flexible array of size 0). 但是只有通过动态内存分配才能有效地创建具有灵活数组成员的结构(其他形式的分配会给您一个大小为0的不可用的灵活数组)。

The older 'struct hack' version of a structure with a variable size array uses an array of size 1 in the structure. 具有可变大小数组的结构的较旧“结构破解”版本在结构中使用大小为1的数组。 You can create global versions of such a structure with an array of size 1. 您可以使用大小为1的数组创建此类结构的全局版本。

But basically, you are trying to do what the language prohibits you from doing, and not very surprisingly, you are failing. 但基本上,您正在尝试执行该语言禁止您执行的操作,并且并不奇怪,您正在失败。

What you do about this depends on what you need. 您如何处理取决于您的需求。 Global variables are inherently somewhat undesirable, so there's an element of "you should be trying to avoid doing this". 全局变量从本质上来说是不希望有的,因此有一个元素“您应该尝试避免这样做”。 That said, the rules apply to file scope ( static ) variables too, and those have many uses. 也就是说,规则也适用于文件范围( static )变量,并且具有许多用途。

You can use an explicit pointer in place of the array, and have separate allocations of the body of the struct MyStruct2 and its array of struct MyStruct1 members. 您可以使用显式指针代替数组,并对struct MyStruct2的主体及其struct MyStruct1成员的数组进行单独分配。 You can forgo the global variable and use dynamically allocated structures with a flexible array member. 您可以放弃全局变量,并通过灵活的数组成员使用动态分配的结构。

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

This creates an struct MyStruct2 (as shown at the top of this answer) with N members in the array. 这将创建一个具有数组中N成员的struct MyStruct2 (如该答案的顶部所示)。 Without any further changes, you can use ms2->b[0] through ms2->b[N-1] (well, apart from error checking that the malloc() succeeded). 无需进行任何进一步的更改,就可以使用ms2->b[0]ms2->b[N-1] (好,除了错误检查malloc()成功外)。

It is not possible to declare a variable-size struct , neither locally nor globally. 不可能在本地或全局声明可变大小的struct Every type has a fixed size determined at compile time. 每种类型在编译时都具有固定的大小。

The error message you report is surprising, however. 但是,您报告的错误消息令人惊讶。 If all the declarations you gave are at file scope, in the same file, in the order you gave them, then the initializer for variable a is a compile-time constant. 如果您给出的所有声明都位于文件范围内,并且按照给定的顺序位于同一文件中,则变量a的初始化程序一个编译时常量。 However, it is not a proper initializer for a struct MyStruct2 , 但是,它不是struct MyStruct2的适当初始化struct MyStruct2

  • because it specifies more elements than that struct type has members, 因为它指定的元素多于该struct类型具有的成员,
  • because the initializer element for ab is an initializer for a struct MyStruct1 instead of for an array of such, and 因为ab的初始值设定项元素是struct MyStruct1的初始值struct MyStruct1而不是此类数组的初始值struct MyStruct1
  • because even if you converted the last two initializer elements into one array initializer, it has more elements than there are elements in ab (ie more than zero). 因为即使将最后两个初始值设定项元素转换为一个数组初始值设定项,也要拥有比ab中的元素更多的元素(即大于零)。

If you want a dynamically-sized array, whether as a variable in its own right or as a member of a struct , then you must declare a pointer to it, and allocate memory for the elements dynamically. 如果您想要一个动态大小的数组,无论是作为变量本身还是作为struct的成员,则必须声明一个指向它的指针,并为元素动态分配内存。 In that case, the elements are not themselves part of the struct ; 在这种情况下,元素本身不是struct一部分; only the pointer to them is. 只有指向它们的指针。 (That is different, by the way, from a fixed size array whose size is implicit in its initializer; these are possible only for independent types, though, not for types of struct or union members). (顺便说一下,这与大小固定在其初始值设定项中的固定大小的数组不同;但这仅适用于独立类型,而不适用于structunion成员的类型)。

EDIT: C99 flexible arrays are a possible alternative, as ShafikYaghmour commented. 编辑:正如ShafikYaghmour所说,C99灵活数组是一种可能的选择。 These are similar, but not identical, to a struct element that is a pointer to a dynamically-allocated array. 它们与作为动态分配数组指针的struct元素相似但不相同。 In that case, however, you not only cannot statically declare the array elements, you also cannot statically declare instances of the struct itself, so this wouldn't at all get around your initializer issue. 但是,在那种情况下,您不仅不能静态声明数组元素,还不能静态声明该struct本身的实例,因此这根本不会解决初始化程序问题。 There are several other quirks and limitations. 还有其他一些怪癖和局限性。 Personally I see few advantages to flexible arrays, but they do make it a bit easier to properly free struct instances. 就我个人而言,我没有看到灵活数组的优点,但是它们确实使正确释放结构实例变得容易一些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM