12

我有一些关于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++ 中都被禁止?数组进入全局和局部范围的行为不同的原因是什么?

4

5 回答 5

12

是的,您的推理是正确的,这就是 C 和 C++ 看待这些不同形式的数组声明和定义的方式。

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

这为 C 留下了关于包含const限定对象的长度表达式的小差距,这是不允许的。这是因为此类对象不被 C 标准视为“整数常量表达式”。这可能会在未来的版本中改变,但到目前为止,C 委员会还没有发现有必要允许这样的事情:在 C 中有一些enum常量扮演着这个角色。它们唯一的限制是它们仅限于int在 C 中,也有它们会很好size_t

于 2012-12-28T23:22:46.373 回答
4

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

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

于 2012-12-28T20:37:14.420 回答
3

禁止和不允许是有区别的。;-)

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

现在您想在函数之外使用 VLA。为什么?在程序启动期间避免单个 malloc 调用并没有什么可以快速赢得的。我们应该为具有静态生命周期的变量使用什么堆栈空间?

于 2012-12-28T20:29:36.667 回答
3

我认为根本原因是全局变量具有链接,它的大小必须在编译时知道。如果不是,如何链接程序?

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

于 2012-12-28T20:37:08.797 回答
0

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

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

....在另一个文件中:

extern int a;
extern int b;

链接器必须知道 a 和 be 在链接时彼此相关的位置,否则将无法在加载时正确修复它们。

于 2012-12-28T21:08:22.350 回答