变长数组什么时候合法?

发布于 2024-11-02 11:29:35 字数 359 浏览 1 评论 0 原文

我不是 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

I'm not a C++ expert, but as far as I know this code should fail due to size not being constant:

#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;
}

Why does this work when I compile that with gcc (better say g++)?

./test 7
7
/test 2 
2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

青芜 2024-11-09 11:29:35

要从堆栈或堆中为变量分配内存,需要知道变量的大小。 C++ 编译器可以自己决定如何分配内存,但 C++ 已经公开了他们期望 C++ 编译器如何处理这种情况,因此 c++ std 要求编译器供应商发布他们的内存处理。这是通过 sizeof 运算符发生的。该运算符完全在编译时计算。数组大小的编译时限制来自此要求。

int arr[10];
std::cout << sizeof(arr) << std::endl

由于每个变量和类型都支持 sizeof,因此需要在 C++ 编译时计算它们的大小。因此,可变长度数组在 C++ 中是不可能的。

此要求还有另一个非常重要的限制。原则上,C++ 编译器供应商可以计算 C++ 程序堆栈所需的最大内存量,只要不存在以下问题:对于递归函数,您无法计算程序使用的堆栈大小,但对于其他所有内容,堆栈的大小可以通过执行以下操作来计算:

  1. 对堆栈帧中的每个变量使用 sizeof(a) 对
  2. 变量的大小求和以获得该堆栈帧所需的内存量
  3. 列出所有可能的堆栈帧并计算它们的大小
  4. 选择具有最大的调用堆栈size
  5. 选择该大小作为程序堆栈的大小。

不幸的是,递归函数破坏了整个方案。并且需要全局程序的流程分析来识别哪些函数可能具有无限的调用堆栈。但是编译时 sizeof 运算符的限制很重要,否则我们的 C++ 程序会随机耗尽堆栈空间,导致崩溃和不稳定。这是不可接受的。因此,每个变量和类型都支持编译时 sizeof 运算符。

VLA 支持要求编译器可以生成代码,其中通常生成的偏移量作为结果机器代码的常量实际上可以在运行时修改。符合标准的 C++ 编译器通常没有能力执行此操作。 C 决定添加此支持,因此 C 编译器可以做到这一点。但在此过程中他们需要打破 sizeof 运算符。不再可以在编译时计算大小。 C 标准中指定的 VLA 支持存在很大问题:

  1. 您不能将 VLA 放入结构或类中
  2. 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.

int arr[10];
std::cout << sizeof(arr) << std::endl

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:

  1. use sizeof(a) for every variable in stack frame
  2. sum the sizes of the variables to get amount of memory required for that stack frame
  3. list all possible stack frames and calculate their sizes
  4. Pick the call stack that has largest size
  5. choose that size as the size of your program's stack.

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:

  1. you cannot put VLA inside a struct or class
  2. VLA's are basically restricted to the local function scope

These problems were already solved in c++ via std::vector which do not have any of these problems.

谈情不如逗狗 2024-11-09 11:29:35

这是C99 中的新功能列表,其中添加了可变长度数组

另请参阅 数组声明符 “nofollow">N1548ISO/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.

烟花易冷人易散 2024-11-09 11:29:35

这是一个非标准的 GCC 扩展 - 其他编译器(例如 Visual C++)不支持它。

That's a non-standard GCC extension - other compilers like Visual C++ don't support that.

失去的东西太少 2024-11-09 11:29:35

这是 C99 的一项功能,允许您像在堆栈上那样声明数组。

It's a C99 feature that allows you to declare arrays like that on the stack.

笑看君怀她人 2024-11-09 11:29:35

因为您不将 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++.

温暖的光 2024-11-09 11:29:35

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 手册中的标准部分介绍了更多详细信息。值得注意的是,从 2011 年 C 标准开始,可变长度数组 (VLA) 现在是可选的。

c99 supports variable length arrays(VLA) but neither c90 nor C++ supports variable length arrays, but gcc support this as an extension in both C and C++ you can see this more clearly if you compile with these arguments:

gcc -std=c89 -pedantic

this will give you the following warning:

warning: ISO C90 forbids variable length array ‘array’ [-Wvla]

or with g++:

g++ -pedantic

will give you this warning:

warning: ISO C++ forbids variable length array ‘array’ [-Wvla]

this standards section in the gcc manual goes into more details. Important to note that as of the 2011 C standard variable length arrays(VLA) are now optional.

筑梦 2024-11-09 11:29:35

即使没有 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文