为什么可变长度数组不能全局使用?

Why doesn't work Variable length array as a globally?

如果我在本地写可变长度数组,像这样:

#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];

来自标准 6.7.6.2

If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.

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

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

数组的大小取决于它和sz(在我们的例子中是另一个跨国单位)之间的初始化顺序。它可以生成一个 0 大小的数组(格式错误)。正在构建的程序的正确性不应该依赖于这些东西。

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

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

但为什么在这种情况下完全使用 VLA?只需使用常量表达式 10.

指定大小即可

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

你已经 ,但为了详细说明 为什么 部分,让我加两分。

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

The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value throughout its lifetime.34)

然后,静态存储时长:(引用P3)

An object whose identifier is declared without the storage-class specifier _Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.

并且,链接:(§6.2.3/P5 章)

[...] If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

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

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

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

[...] If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.

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

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