C++动态大小的静态数组谜题

7

当我试图向某人解释为什么C++静态数组不能动态调整大小时,我发现gcc并不同意我的说法。考虑到array的维度argc在编译时并不知道,下面的代码是如何编译的呢?

#include <iostream>
int main(int argc, char* argv[]) {
    int array[argc];
    for(int i = 0; i < argc; i++) array[i] = argv[i][0];
    for(int i = 0; i < argc; i++) std::cout << i << ": " << char(array[i]) << std::endl;
    //for(int i = 0; i < 100; i++) { std::cout << i << " "; std::cout.flush(); array[i] = 0; }
    return 0;
}

我使用gcc 4.2.1进行了测试,并指定了-Wall,编译器没有任何反应。如果取消最后一个循环的注释,在将值赋给array[53]时会导致段错误。

我之前在array声明之前和之后放置了保护数组,并用零填充它们,确信程序一定会破坏其堆栈的某些部分,但是gcc重新排列了堆栈上的变量,使我无法观察到任何数据损坏。

显然,我并不试图让这段代码“工作”。我只是想知道为什么gcc认为它可以编译该代码。任何提示或解释都将不胜感激。

更新:感谢所有人的帮助和极快的回复!


我认为C99允许动态数组:http://bytes.com/topic/c/answers/770297-c99-dynamic-array - Kevin
3
另一个基本问题是你在使用一个编译器来测试某种语言是否可行。你可以在gcc中指定标准,并要求严格遵守标准(-pedantic?),但你没有这样做,因此允许了编译器扩展。 - David Thornley
5个回答

10

6
那是C99标准的一部分,被称为可变长度数组。但它并不属于C++。
你也可以使用alloca函数,虽然它不是标准的C++函数,但得到了广泛支持。
int main(int argc, char* argv[])
{
    int* array = (int*) alloca( argc * sizeof(int) );
    array[0] = 123;
    // array automatically deallocated here. Don't call free(array)!
}

3
这些被称为可变长度数组(自C99以来可用),只能声明为自动变量 - 尝试在前面加上static,编译器将拒绝它。这仅涉及使用变量而不是常量偏移量来增加堆栈指针,不会更多。
在可变长度数组引入之前,通过alloca函数在堆栈上分配可变大小的对象。

2

可变大小的基于栈的数组是G++扩展,因此在那里完全合法。但是,它们不属于标准。基于栈的数组在大多数实现中确实可以是可变大小的,但标准并未强制执行此项规定。


2

C++中的数组大小只能使用常量表达式指定。通过非const定义数组大小要么是C99的一部分,要么是GCC强加给我们的可怕扩展。在编译C++代码时,可以使用-pedantic标志来消除大部分GCC扩展。


你为什么认为这是一个可怕的特性?它允许你通过只分配所需的空间来更有效地使用可用的堆栈空间。 - Blagovest Buyukliev
@Blagovest 你的意思是使用基于堆栈的普通数组吗?那太糟糕了,C社区中的许多人(以及C++社区中的每个人)都这么认为。此外,它永远不会成为C++的一部分,因此这是一个可移植性问题。 - user2100815

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接