什么时候变长数组是合法的?
When are variable-length arrays legal?
我不是c++专家,但据我所知,这段代码应该失败,因为size
不是恒定的:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
int size = *argv[1] - 48;
char array [size];
cout<<sizeof(array)<<endl;
return 0;
}
当我用gcc(最好说是g++)编译时,为什么这个工作?
./test 7
7
/test 2
2
要从堆栈或堆中为变量分配内存,需要知道变量的大小。c++编译器可以自己决定它们如何分配内存,但是c++已经公开了它们期望c++编译器如何处理这种情况,因此c++ std要求编译器供应商发布它们的内存处理。这是通过sizeof操作符实现的。此操作符完全在编译时计算。对数组大小的编译时限制来自于这个要求。
int arr[10];
std::cout << sizeof(arr) << std::endl
因为每个变量和类型都支持sizeof,所以它们的大小需要在c++编译时计算。因此,可变长度数组在c++中是不可能的。
这个要求还有另一个非常重要的限制。原则上,c++编译器供应商可以计算c++程序栈所需的最大内存量,只要不存在一个问题:对于递归函数,您无法计算程序使用的堆栈大小,但对于其他所有功能,堆栈大小可以通过以下操作计算:
- 对堆栈帧 中的每个变量使用sizeof(a)
- 将变量的大小相加,以获得该堆栈帧所需的内存量
- 列出所有可能的堆栈帧并计算它们的大小
- 选择具有最大大小的调用堆栈
- 选择该大小作为程序栈的大小。
不幸的是,递归函数破坏了整个方案。并且需要全局程序流分析来识别哪些函数可能有无限的调用栈。但是编译时sizeof操作符的限制很重要,否则我们的c++程序会随机耗尽堆栈空间,导致崩溃和不稳定。这是不可接受的。因此,每个变量和类型都支持编译时sizeof操作符。
VLA支持要求编译器可以生成这样的代码:通常生成的作为结果机器码常量的偏移量实际上可以在运行时修改。符合标准的c++编译器通常不具备这种能力。C决定添加这种支持,因此C编译器可以做到这一点。但是在这个过程中,他们需要打破sizeof运算符。不再可以在编译时计算大小。C标准中指定的VLA支持存在很大的问题:
- 不能将VLA放在结构体或类中
- VLA基本上局限于局部函数范围
这些问题在c++中已经通过std::vector解决了,而std::vector不存在这些问题
以下是C99增加可变长度数组的新特性列表。
也见N1548的数组声明符 (ISO/IEC 9899:201x Committee Draft - December 2, 2010 N1548),其中详细说明。
这是一个非标准的GCC扩展-其他编译器如Visual c++不支持。
这是C99的一个特性,允许你在堆栈上声明这样的数组
c99
支持可变长度数组(VLA
),但c90
和c++都不支持可变长度数组,但gcc
在C和c++中都支持此扩展,如果使用这些参数进行编译,您可以更清楚地看到这一点:
gcc -std=c89 -pedantic
这会给你以下警告:
warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
或与g++
:
g++ -pedantic
会给你这样的警告:
warning: ISO C++ forbids variable length array ‘array’ [-Wvla]
gcc
手册中的standards
部分将详细介绍。值得注意的是,自2011年C标准可变长度数组(VLA
)现在是可选的。
即使没有VLA扩展,当编译器在编译时未能推断出维度表达式是未知的时,代码也可以编译。还是UB
因为您没有将g++作为c++编译器调用。如果我尝试它,我得到一个警告,明确指出"ISO c++禁止可变长度数组"。但是我的makefile包含选项-std=c++98
,至少当我想编译可移植的c++时。
- 通过JNI传递数据数组的最快方法是什么
- 讨论 - 创建矩阵时的数组与向量的向量 - 什么是最实用的选择
- 编译器对数组声明大小的计算。什么时候发生?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 当该数组的索引中没有元素时,指针指向什么?
- 给定一个整数数组,需要在Max_Heap上运行操作。得到错误"segmentation fault",有什么想法吗?(C++)
- 从字符数组的元素中减去'a'是什么意思
- 这种用于查找连续子数组中最大和的递归算法有什么优势吗?
- 字符数组前面的加号是什么意思?
- 初始化数组、"memset"或" {//value} "的最佳方法是什么?
- 在C++中,建议通过数组循环的方式是什么?
- C++ 未初始化的本地(非全局)int 数组中的元素类型到底是什么?
- C++数组中的初始值设定项是什么?
- 如果我在字符数组上使用 close() 会发生什么?
- 指向数组基址的指针而不是指向第一个元素的指针有什么优点?
- 我什么时候应该使用删除?(在动态创建的2D数组之后未删除的后果)
- 什么时候需要将数组的大小作为参数传递?
- 什么时候应该在字符数组上使用std::string
- 什么时候变长数组是合法的?