msc*_*msc 4 c gcc variable-length-array
如果我将可变长度数组写为本地,如下所示:
#include <stdio.h>
int main()
{
int i=1;
int a[i];
printf("%zu",sizeof(a));
}
Run Code Online (Sandbox Code Playgroud)
它在GCC编译器中运行良好.
但是,如果我将可变长度数组写为全局,如下所示:
#include <stdio.h>
int i=1;
int a[i];
int main()
{
printf("%zu",sizeof(a));
}
Run Code Online (Sandbox Code Playgroud)
然后,GCC编译器给出以下错误:
prog.c:4:5: error: variably modified 'a' at file scope
int a[i];
Run Code Online (Sandbox Code Playgroud)
这是不允许的,因为除非它被限制到极端,否则它可能非常容易出错。考虑一下:
extern const int sz; // Another TU
int a[sz];
Run Code Online (Sandbox Code Playgroud)
数组的大小取决于它和sz(在我们的例子中是另一个跨国单位)之间的初始化顺序。它可以产生一个 0 大小的数组(格式错误)。正在构建的程序的正确性不应该依赖于这些东西。
因此,如果我们将其大小限制为仅当前 TU 中的变量,我们最终会得到:
const int sz = 10;
int a[sz];
Run Code Online (Sandbox Code Playgroud)
但为什么在这种情况下完全使用 VLA?只需使用常量表达式 10 指定大小。
这不是一个有用的功能。更不用说,正如@MM 指出的那样,它违背了轻松允许将静态数据预先构建到二进制文件中的设计目标。
你已经有了答案,但只是为了详细说明为什么部分,让我加上我的两分钱。
首先,关于生命周期:(引用C11,章节 §6.2.4/P2)
对象的生命周期是程序执行的一部分,在此期间保证为其保留存储空间。一个对象存在,有一个常量地址,33) 并在整个生命周期中保留其最后存储的值。 34)
然后,静态存储持续时间:(引用 P3)
一个对象,其标识符在没有存储类说明符的情况下声明
_Thread_local,并且具有外部或内部链接或存储类说明符static,具有静态存储持续时间。它的生命周期是程序的整个执行过程,它的存储值在程序启动之前只初始化一次。
和,链接:(第 6.2.3/P5 章)
[...] 如果对象的标识符声明具有文件范围且没有存储类说明符,则其链接是外部的。
所以,在这种情况下,a就是要有静态的存储期。
现在,根据定义,VLA 维度是在运行时获取的,因此编译器无法知道和分配内存/存储并在开始时对其进行初始化(在程序启动之前,根据静态存储持续时间的需要),因此这是一个冲突。
如C11第 6.7.6.2 章所述,标准明确禁止这样做。
[...] 如果标识符被声明为具有静态或线程存储持续时间的对象,则它不应具有可变长度数组类型。
因为标准是这么说的。但这不是很有帮助;原因为什么这不是标准允许,是所有文件范围的变量必须在main()被调用之前被初始化。这反过来意味着它们必须仅由编译时常量组成。
VLA 的目的是在运行时获取大小。我们不能有一个大小在编译时和运行时都确定的数组。如果您需要文件范围内的可变大小数组,请使用指针,然后在运行时让它指向已分配的数组,例如使用 malloc() 分配的数组。