【问题标题】:Declare Global Struct Variable With Variable Size In C在 C 中声明具有可变大小的全局结构变量
【发布时间】:2015-01-07 07:17:19
【问题描述】:

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

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 } };

但是,我得到一个“Initializer Element is not a compile-time constant”。

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

【问题讨论】:

  • 编译器会在编译代码时为你的结构分配空间。由于您无法告诉它您的结构有多大,因为这只会在执行时发生,所以您想要的实际上是不可能的。编译器无法进行时间旅行。您必须简单地为您的结构放入一个指针,然后稍后再分配适当的空间。
  • 也许flexible arrays 是一个选择。
  • @MarcB - 所以没有办法告诉编译器 a 应该有 x MyStruct1s 的空间。或者甚至分配适当大小的空间,以便稍后插入值?
  • 你可以给它你想要的最大可能大小,但如果你很少使用那么多,那么你将浪费大量的 ram 为几乎从未发生过的事情保留空间。这就是为什么有 malloc() - 根据需要在运行时动态分配内存。

标签: c struct


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

    具有可变大小数组的结构的旧“struct hack”版本在结构中使用大小为 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() 成功的错误)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 2018-03-22
      相关资源
      最近更新 更多