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

Posted

技术标签:

【中文标题】C 和 C++ 中的可变长度数组 (VLA)【英文标题】:Variable length arrays (VLA) in C and C++ 【发布时间】:2012-12-14 01:18:17 【问题描述】:

可能重复:Variably modified array at file scope

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

【问题讨论】:

假设允许全局 VLA。它们的(可变)大小何时实际定义? @cnicutar 好吧......就像所有的 VLA,在执行时间上,就像其他范围一样。我知道这不是答案,但我想知道为什么。 ***.com/a/5052083/174605 是的,所以一个全局 VLA,你怎么知道值是什么时候定义的?为了使它有意义,它要求您可以在构建数组之前设置大小的值 - 并且需要在编译时知道大小以告诉系统操作系统在加载可执行文件时需要多少空间. 投票重新打开,因为这不是链接的“重复”的重复。链接的问题询问如何避免文件范围内不允许 VLA 的错误;这个问题询问为什么文件范围内不允许使用 VLA。 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

是的,我知道 const 关键字在 C++ 中创建了一个编译时常量,而在 C 中却没有,我已经对此问题发表了评论。【参考方案4】:

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

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

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

extern int a;
extern int b;

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

【讨论】:

【参考方案5】:

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

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

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

【讨论】:

终于有人证明已经阅读了整个问题! (为此+1)恕我直言,这个问题不是duplicate,因为我关注的是其他事实。感谢您的解释,感谢您回答了我几乎所有的问题。

以上是关于C 和 C++ 中的可变长度数组 (VLA)的主要内容,如果未能解决你的问题,请参考以下文章

在 MS Visual C++ 中启用 VLA(可变长度数组)?

C++ 替代 C99 VLA(目标:保持性能)

在其内存应该已被释放后访问可变长度数组

C 可变长度数组存储持续时间

为啥零长度 VLA 是 UB?

使用可变长度数组是不是安全?