这似乎是一个初学者的问题,但我对编译器通常创建变量维数组的方式感兴趣,如下面的程序。
#include<iostream>
int main(){
int n;
std::cin>>n;
int a[n];
}
根据我所知,在C中,所有初始值都必须是常量,以便编译器知道在函数内保留多少内存,通常是通过减去堆栈指针来容纳元素的数量数组成立。
这对我有意义。 但是,我不太了解编译器如何处理上述程序,因为它似乎与G ++(MinGW)一起使用,但是使用Cl,Microsoft的C ++编译器失败了。我怀疑GCC通过非标准扩展在堆上分配内存,但我不确定。
此外,微软的编译器并不因标准兼容而闻名,所以如果它对待上述程序的方式实际上可能出错,我不会感到惊讶。
答案 0 :(得分:12)
在C标准的C99版本中,允许使用可变长度数组。但是,它们不允许在任何版本的C ++中使用;你正在看一个G ++扩展。请注意,Microsoft的C编译器不完全支持C99;由于G ++支持C99,因此很容易将VLA支持应用于C ++作为扩展。
关于编译器通常如何实现VLA,它与alloca()
相同(除了它必须保持sizeof
的大小) - 编译器保存原始堆栈指针,然后调整它然而,它计算出它需要的许多字节。缺点是函数进入和退出有点复杂,因为编译器需要存储重置堆栈指针的位置,而不是仅仅通过固定常量进行调整。
答案 1 :(得分:5)
运行时“运行时减去堆栈指针”绝对没有问题。这就是编译器通常如何实现可变长度数组。当实际的数组大小已知时,它们在运行时“减去堆栈指针”。这里的所有都是它的。 (没有必要在堆上分配内存,我不知道是什么让你在GCC中怀疑这一点。)。
在VLA成为该语言的一部分之前很久就可以使用这种功能。 [非标准]函数alloca
就是这样做的。唯一的区别是alloca
分配的内存在函数退出时自动解除分配,而本地VLA必须遵守基于标准块的生存期规则。后者根本不是问题,因为以类似堆栈的方式阻塞嵌套。
换句话说,对于运行时值n
声明
int a[n];
基本上被翻译成类似
的东西int *a = alloca(n * sizeof *a);
加上一些额外的家庭数据来支持sizeof
等的功能(当然,还可以在封闭块的末尾自动恢复原始堆栈指针值。)
答案 2 :(得分:2)
没有版本的C ++允许可变长度数组。只有C99允许它。
GCC允许它作为扩展名。
答案 3 :(得分:2)
int main(){
int n;
std::cin>>n;
int a[n];
}
这不是合法的C ++。 G ++接受可变长度数组作为扩展,但是VLA不是C ++标准的一部分。它们是GCC支持的C99标准的一部分(我不确定在多大程度上),但MSVC没有。