我有一些关于VLA及其行为的概念,我需要澄清。
AFIK自C99起,可以将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 ++中是否被禁止?数组在全局和局部范围内的行为有什么不同?
答案 0 :(得分:5)
C ++不支持VLA,期间。第二个代码片段在C ++中工作的原因是const
关键字在C ++中创建了一个编译时常量;在C中,它没有。
无论您如何声明大小变量,C99都不支持块范围,句点之外的VLA。请注意,C2011使VLA支持可选。
答案 1 :(得分:5)
是的,你的推理是正确的,这就是C和C ++如何查看这些不同形式的数组声明和定义。
正如其他人已经说过的那样,在全球范围内具有真实可变长度(非const
)的VLA很难理解。评估顺序是什么,例如,如果长度表达式将引用不同编译单元的对象? C ++没有VLA,但它在文件范围内对对象进行动态初始化。如果你不得不依赖评估订单,这已经让你头脑疼痛了。
这为C留下了关于包含const
限定对象的长度表达式的小间隙,这是不允许的。这是因为C标准不将这些对象视为“整数常量表达式”。这可能会在未来版本中发生变化,但到目前为止,C委员会认为没有必要允许这样的事情:有enum
个常数在C中发挥作用。他们唯一的限制是他们是在C中限制为int
,最好还有size_t
。
答案 2 :(得分:3)
我认为根本原因是全局变量具有链接,其大小必须在编译时知道。如果没有,怎么可以链接该程序?
局部变量没有链接,并且在堆栈上分配了VLA,它随着程序的运行而动态增长。
答案 3 :(得分:2)
被禁止和不被允许之间存在差异。 ; - )
VLA功能旨在允许为本地数组使用堆栈空间,以避免使用malloc进行堆分配。它主要是速度优化。
现在您想在函数之外使用VLA。为什么?在程序启动期间避免单个malloc调用的速度并不快。我们应该将哪些堆栈空间用于具有静态生命期的变量?
答案 4 :(得分:1)
因此,对于全球VLA来说,其中一个问题(主题有很多变种)可以在这里显示:
int size;
int a;
int v[size];
int b;
.... 在另一个文件中:
extern int a;
extern int b;
链接器必须在链接时知道a和a在哪里相互关联,否则它将无法在加载时正确修复它们。