C++数组维度与C99的变长数组(VLA)

C++数组维度与C99的变长数组(VLA)问题起因前几天在一个 C 学习交流群里边有群友问了一个代码问题 其中它的代码包含了这样的语句 intn scanf d amp n std stringstrs n 看到这样的操作 我没有继续看其他的代码 就直接指出了他的这个问题 我说这种静态数组在编译期就要确定内存大小 你这样肯定有问题 他表示不信 后来他的程序问题找到了并且告诉我 他的这种写法没问题 我当时就

问题起因

前几天在一个C++学习交流群里边有群友问了一个代码问题,其中它的代码包含了这样的语句

int n; scanf("%d",&n); std::string strs[n];

看到这样的操作,我没有继续看其他的代码,就直接指出了他的这个问题,我说这种静态数组在编译期就要确定内存大小,你这样肯定有问题,他表示不信,后来他的程序问题找到了并且告诉我,他的这种写法没问题,我当时就奇怪了,怎么与我一贯的理解不同呢,工作了这么多年,凡是使用数组的地方都是固定大小的。然后我在devC++这个IDE上测试了这个问题,当然编译器是GCC的,结果令我吃惊,还真是没问题。看来涉及到基础的问题,我还是不牢固啊,赶紧翻开《C++Primer》来看

C++Primer关于数组的说法

C++primer中文版第五版101页说到:

数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的,也就是说维度必须是一个常量表达式

unsigned cnt = 42; //不是常量表达式 constexpr unsigned sz = 42;//常量表达式 int arr[10]; //含有10个整数的数组 int *parr[sz]; //含有42个整型指针的数组 string bad[cnt]; //错误:cnt不是常量表达式 string strs[get_size()]; //当get_size是constexpr时正确;否则错误

这么说来我原来的理解是没错的。那么为什么出现上边的问题呢,这就涉及到C99标准了

C99标准的变长数组(VLA)

参见维基百科的解释 https://en.wikipedia.org/wiki/Variable-length_array#C99

The following C99 function allocates a variable-length array of a specified size, fills it with floating-point values, and then passes it to another function for processing. Because the array is declared as an automatic variable, its lifetime ends when read_and_process() returns.

float read_and_process(int n) { float vals[n]; for (int i = 0; i < n; ++i) vals[i] = read_val(); return process(n, vals); }

In C99, the length parameter must come before the variable-length array parameter in function calls.[1]

Linus Torvalds has expressed his displeasure in the past over VLA usage for arrays with predetermined small sizes, with comments like "USING VLA'S IS ACTIVELY STUPID! It generates much more code, and much slower code (and more fragile code), than just using a fixed key size would have done." [6] With the Linux 4.20 kernel, Linux kernel is effectively VLA-free.

注意红字的部分,另外显然Linus不喜欢VLA

编译器对VLA的支持

GCC

还是上边的维基百科

  • The GNU C Compiler allocates memory for VLAs with automatic storage duration on the stack.VLAs, like all objects in C, are limited to SIZE_MAX bytes
  • VLAs can also be allocated on the heap and accessed using a pointer to VLA.

那么我的疑问也得到了解答了,显然GCC是支持VLA的,而且是在栈上分配的内存

Visual C++

我自己在visual studio 2017上尝试了一下,要求数组维度必须是常量表达式

参见该链接

https://docs.microsoft.com/en-us/cpp/c-language/c-language-reference?view=vs-2019

The C Language Reference describes the C programming language as implemented in Microsoft C. The book's organization is based on the ANSI C standard (sometimes referred to as C89) with additional material on the Microsoft extensions to the ANSI C standard.

以及维基百科

https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#C

Although the product originated as an IDE for the C programming language, for many years the compiler's support for that language conformed only to the original edition of the C standard, dating from 1989, but not the C99 revision of the standard. There had been no plans to support C99 even in 2011, more than a decade after its publication

也就是visualC++虽然最初是为了C编程开发的,但是对C标准的支持并不够,C99并不怎么支持,后边还有内容会说到,其实后来的visual IDE 对C99的支持是不完备的

VLA的实现原理

既然数组是变长的,编译的时候又不能确定维度,那么我对怎么实现的很感兴趣,查了一些东西,感觉论坛里这个解释很好。

当有多个变长数组分配时,也就是编译器不能用仅有的几个寄存器保存当前的esp时,编译器就会划分一块区域(这块区域也在栈中,而且是先于变长数组分配划分好的)来记录每个数组的首地址。

所以,变长数组的开销还是小于malloc的。

建议

根据个人的工作经验,还是不太建议使用变长数组,另外这里要注意的是 变长数组而不是动态数组,通常我们谈到动态数组就想到 malloc分配内存,或者是vector,如果遇到使用不确定长度的数组,还是使用vector吧。再者不是所有的编译器都支持VLA。

参考资料

https://www.cnblogs.com/hazir/p/variable_length_array.html

https://blog.csdn.net/_/article/details/

https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#C

https://en.wikipedia.org/wiki/Variable-length_array#C99

https://docs.microsoft.com/en-us/cpp/c-language/c-language-reference?view=vs-2019

《C++ Primer 中文版》第五版

https://bbs.csdn.net/topics/

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218480.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午7:09
下一篇 2026年3月18日 上午7:09


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号