为什么不工作变长数组作为全局?

时间:2017-12-14 08:53:54

标签: c gcc variable-length-array

如果我将可变长度数组写为本地,如下所示:

#include <stdio.h>

int main()
{
    int i=1;
    int a[i];
    printf("%zu",sizeof(a));
}

它在GCC编译器中运行良好。

但是,如果我将可变长度数组写为全局数组,如下所示:

#include <stdio.h>
int i=1;
int a[i];
int main()
{
    printf("%zu",sizeof(a));
}

然后,GCC编译器发出以下错误:

prog.c:4:5: error: variably modified 'a' at file scope
  int a[i];

4 个答案:

答案 0 :(得分:15)

来自标准6.7.6.2

  

如果标识符声明为具有静态或线程的对象   存储持续时间,它不应具有可变长度的数组类型。

答案 1 :(得分:4)

这是不允许的,因为除非它被限制到极端,否则它可能特别容易出错。考虑一下:

extern const int sz; // Another TU
int a[sz];

数组的大小取决于它与sz之间的初始化顺序(在我们的示例中是在另一个跨国单位中)。它可能会产生0大小的数组(格式不正确)。正在建立的程序的正确性不应该取决于这些事情。

因此,如果我们仅将其大小限制为当前TU中的变量,我们最终得到:

const int sz = 10;
int a[sz];

但是在这种情况下为什么要使用VLA呢?只需使用常量表达式10指定大小。

这不是一个有用的功能。更不用说,正如@ M.M所指出的那样,它违背了设计目标,即容易将静态数据预先构建到二进制文件中。

答案 2 :(得分:4)

你已经have the answer,但只是详细说明为什么部分,让我加上我的两分钱。

首先,关于生命期 :(引用C11,章节§6.2.4/ P2)

  

对象的生命周期是存储期间程序执行的一部分   保证为它保留。存在一个对象,具有恒定的地址,33)并保留   它在其整个生命周期中的最后存储价值.34)

然后,静态存储持续时间 :(引用P3)

  

在没有存储类说明符的情况下声明其标识符的对象   _Thread_local,可以是外部或内部链接,也可以是存储类   说明符static具有静态存储持续时间。它的一生就是整个执行   在程序启动之前,程序及其存储的值只初始化一次。

链接 :(章节§6.2.3/ P5)

  

[...]如果   对象标识符的声明具有文件范围,没有存储类说明符,   它的联系是外部的。

因此,在这种情况下,a将具有静态存储持续时间。

现在,根据定义,VLA维度是在运行时获取的,所以现在编译器可以知道并分配内存/存储并在开始初始化它(在程序之前)启动,根据静态存储持续时间的要求),因此这是冲突。

C11第6.7.6.2章所述,标准明确禁止

  

[...]如果标识符被声明为具有静态或线程存储的对象   持续时间,它不应具有可变长度数组类型。

答案 3 :(得分:4)

因为标准是这样说的。但这并不是很有帮助; 为什么这个标准不允许的原因是所有文件范围变量必须在调用main()之前初始化。这反过来意味着它们必须只包含编译时常量。

VLA的目的是在运行时获取大小。我们不能有一个数组,在编译时和运行时确定大小。如果在文件范围需要可变大小的数组,请使用指针,然后在运行时将其指向已分配的数组,例如使用malloc()分配的数组。