变长数组什么时候合法?
我不是 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
要从堆栈或堆中为变量分配内存,需要知道变量的大小。 C++ 编译器可以自己决定如何分配内存,但 C++ 已经公开了他们期望 C++ 编译器如何处理这种情况,因此 c++ std 要求编译器供应商发布他们的内存处理。这是通过 sizeof 运算符发生的。该运算符完全在编译时计算。数组大小的编译时限制来自此要求。
由于每个变量和类型都支持 sizeof,因此需要在 C++ 编译时计算它们的大小。因此,可变长度数组在 C++ 中是不可能的。
此要求还有另一个非常重要的限制。原则上,C++ 编译器供应商可以计算 C++ 程序堆栈所需的最大内存量,只要不存在以下问题:对于递归函数,您无法计算程序使用的堆栈大小,但对于其他所有内容,堆栈的大小可以通过执行以下操作来计算:
不幸的是,递归函数破坏了整个方案。并且需要全局程序的流程分析来识别哪些函数可能具有无限的调用堆栈。但是编译时 sizeof 运算符的限制很重要,否则我们的 C++ 程序会随机耗尽堆栈空间,导致崩溃和不稳定。这是不可接受的。因此,每个变量和类型都支持编译时 sizeof 运算符。
VLA 支持要求编译器可以生成代码,其中通常生成的偏移量作为结果机器代码的常量实际上可以在运行时修改。符合标准的 C++ 编译器通常没有能力执行此操作。 C 决定添加此支持,因此 C 编译器可以做到这一点。但在此过程中他们需要打破 sizeof 运算符。不再可以在编译时计算大小。 C 标准中指定的 VLA 支持存在很大问题:
这些问题已经在 C++ 中通过 std::vector 解决了,而 std::vector 不存在任何这些问题。
To allocate memory from stack or heap for a variable, the size of the variable need to be known. C++ compilers can decide themselves how they allocate memory, but c++ has made it public how they expect c++ compilers to handle the situation, and thus c++ std requires that compiler vendors publish their memory handling. This happens via sizeof operator. This operator is calculated completely in compile-time. The compile-time restriction for the array sizes comes from this requirement.
since every variable and type supports sizeof, their sizes need to be calculated on compile-time in c++. Thus variable-length arrays are impossible in c++.
There is another very important restriction flowing from this requirement. In principle c++ compiler vendors could calculate maximum amount of memory required for c++ program's stack, if only there weren't one problem: for recursive functions, you cannot calculate stack size used by the program, but for everything else, the size of stack can be calculated by doing the following:
Unfortunately, recursive functions break the whole scheme. And it would need global program's flow analysis to regognize which functions have possibly infinite call stacks. But the limitation for compile-time sizeof operator is important or our c++ programs would randomly run out of stack space, causing crashes and unstability. And this is unacceptable. Thus every variable and type supports compile-time sizeof operator.
VLA support requires that compilers can generate code where offsets normally generated to as constants to the resulting machine code are actually modifiable on runtime. Standard conforming c++ compilers normally do not have ability to do this. C decided to add this support and thus C compilers can do it. But in the process they needed to break the sizeof operator. No longer can the sizes be calculated on compile-time. VLA support as specified in the C standard has big problems:
These problems were already solved in c++ via std::vector which do not have any of these problems.
这是C99 中的新功能列表,其中添加了可变长度数组。
另请参阅 数组声明符 “nofollow">N1548(ISO/IEC 9899:201x 委员会草案 — 2010 年 12 月 2 日 N1548)详细介绍了它。
Here is a list of new features in C99 which adds variable length arrays.
Also see $6.7.6.2/4 Array declarators of N1548(ISO/IEC 9899:201x Committee Draft — December 2, 2010 N1548) which details it.
这是一个非标准的 GCC 扩展 - 其他编译器(例如 Visual C++)不支持它。
That's a non-standard GCC extension - other compilers like Visual C++ don't support that.
这是 C99 的一项功能,允许您像在堆栈上那样声明数组。
It's a C99 feature that allows you to declare arrays like that on the stack.
因为您不将 g++ 作为 C++ 编译器调用。如果我尝试它,我会收到一条警告,明确指出“ISO C++ 禁止可变长度数组”。但我的 makefile 包含选项
-std=c++98
,至少当我想编译可移植的 C++ 时是这样。Because you don't invoke g++ as a C++ compiler. If I try it, I get a warning, stating clearly that "ISO C++ forbids variable length array". But my makefiles include the option
-std=c++98
, at least when I want to compile portable C++.c99
支持变长数组(VLA
),但c90
和 C++ 都不支持变长数组,但gcc
支持作为 C 和 C++ 中的扩展 你可以看到这更清楚如果你使用这些参数进行编译:这会给你以下警告:
或使用
g++
:会给你这个警告:
这个
gcc
手册中的标准
部分介绍了更多详细信息。值得注意的是,从 2011 年 C 标准开始,可变长度数组 (VLA
) 现在是可选的。c99
supports variable length arrays(VLA
) but neitherc90
nor C++ supports variable length arrays, butgcc
support this as an extension in both C and C++ you can see this more clearly if you compile with these arguments:this will give you the following warning:
or with
g++
:will give you this warning:
this
standards
section in thegcc
manual goes into more details. Important to note that as of the 2011 C standard variable length arrays(VLA
) are now optional.即使没有 VLA 扩展,当编译器无法推断出编译时未知维度表达式时,代码也可以编译。依然是UB。
Even without VLA extensions, the code can compile when the compiler has failed to deduce that the dimension expression is not known at compile-time. It's still UB.