为什么可变长度数组不能全局使用?
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() 分配的数组。
如果我在本地写可变长度数组,像这样:
#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 specifierstatic
, 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() 分配的数组。