C和C ++中的可变长度数组(VLA)

可能重复:
在文件范围内可变修改的数组

我有一些关于VLA及其行为的概念,我需要澄清一下。

自C99起AFIK可以将VLA声明为本地范围:

int main(int argc, char **argv) { // function 'main' scope int size = 100; int array[size]; return 0; } 

但它在全球范围内被禁止:

 const int global_size = 100; int global_array[global_size]; // forbidden in C99, allowed in C++ int main(int argc, char **argv) { int local_size = 100; int local_array[local_size]; return 0; } 

上面的代码在C99中声明了一个VLA,因为const修饰符不会创建编译时值。 在C ++中, global_size是一个编译时值,因此, global_array不会成为VLA。

我需要知道的是:我的推理是否正确? 我描述的行为是正确的吗?

我也想知道:为什么不允许全球范围内的VLA? 在C和C ++中是否被禁止? 数组在全局和局部范围内的行为有什么不同?

是的,你的推理是正确的,这就是C和C ++如何查看这些不同forms的数组声明和定义。

正如其他人已经说过的那样,在全球范围内具有真正可变长度(非常数)的VLA很难理解。 评估顺序是什么,例如,如果长度表达式将引用不同编译单元的对象? C ++没有VLA,但它在文件范围内对对象进行动态初始化。 如果你不得不依赖评估订单,那么这已经让你头脑疼痛了。

这为C留下了关于包含const限定对象的长度表达式的小间隙,这是不允许的。 这是因为C标准不将这些对象视为“整数常量表达式”。 这可能会在未来的版本中发生变化,但到目前为止,C委员会并没有发现有必要允许这样的事情:有一些enum常量在C中发挥作用。他们唯一的限制是它们仅限于int in C,还有它们size_t会很高兴。

C ++不支持VLA,期间。 第二个代码片段在C ++中工作的原因是const关键字在C ++中创建了一个编译时常量; 在C中,它没有。

无论您如何声明大小变量,C99都不支持块范围,句点之外的VLA。 请注意,C2011使VLA支持可选。

我认为根本原因是全局变量具有链接,其大小必须在编译时知道。 如果没有,怎么可以链接该程序?

局部变量没有链接,并且堆栈上分配了VLA,它随着程序的运行而动态增长。

被禁止和不被允许之间存在差异。 😉

VLAfunction旨在允许为本地数组使用堆栈空间,以避免使用malloc进行堆分配。 它主要是速度优化。

现在,您希望在函数之外使用VLA。 为什么? 在程序启动期间避免单个malloc调用的速度并不快。 我们应该将哪些堆栈空间用于具有静态生命周期的变量?

因此,对于全球VLA,可以在此处显示其中一个问题(主题上有许多变体):

 int size; int a; int v[size]; int b; 

….在另一个文件中:

 extern int a; extern int b; 

链接器必须在链接时知道a和a在哪里相互关联,否则它将无法在加载时正确地修复它们。