18

我有一个简单的函数,其中根据 int 参数声明数组的大小。

    void f(int n){
        char a[n];
    };

    int main() {
        return 0;
    }

这段代码在GNU C++上编译得很好,但在 MSVC 2005 上编译得不好。

我收到以下编译错误:

    .\main.cpp(4) : error C2057: expected constant expression
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
    .\main.cpp(4) : error C2133: 'a' : unknown size

我能做些什么来纠正这个问题?

(我有兴趣使用 MSVC 进行这项工作,而不使用 new/delete)

4

7 回答 7

28

您发现它是 Gnu 编译器对 C++ 语言的扩展之一。在这种情况下,Visual C++ 是完全正确的。C++ 中的数组必须使用编译时常量表达式的大小来定义。

在 1999 年对 C 语言的更新中添加了一个特性,称为可变长度数组,这是合法的。如果你能找到一个支持C99的C编译器,这并不容易。但这个特性不是标准 C++ 的一部分,也不会在 C++ 标准的下一次更新中添加。

C++ 中有两种解决方案。第一个是使用 std::vector,第二个只是使用 operator new []

char *a = new char [n];

在我写答案时,另一个人发布了使用 _alloca 的建议。我强烈建议不要这样做。您只需将一种非标准的、不可移植的方法换成另一种特定于编译器的方法。

于 2008-11-23T04:44:01.930 回答
10

您从堆栈分配的方法是 g++ 扩展。要在 MSVC 下做同样的事情,你需要使用 _alloca:

char *a = (char *)_alloca(n);
于 2008-11-23T04:40:29.380 回答
5

您正在使用不是标准的东西。实际上它是标准 C 但不是 C++。这是多么奇特啊!

再解释一下,运行时大小的堆栈数组不是 C++ 的一部分,而是 C99 的一部分,这是 C 的最新标准。这就是为什么有些编译器会得到它,而其他编译器不会。我建议不要使用它,以避免编译器兼容性问题。

正如 strager 所发布的,该功能的替代实现将使用 new 和 delete。

于 2008-11-23T04:47:55.747 回答
2

您可以使用 new/delete 在堆上分配/释放内存。这比使用 char[n] 更慢并且可能更容易出错,但遗憾的是,它还不是 C++ 标准的一部分。

您可以将 boost 的作用域数组类用于使用 new[] 的异常安全方法。当a超出范围时,会自动调用 delete[] 。

void f(int n) {
    boost::scoped_array<char> a(new char[n]);

    /* Code here. */
}

您还可以使用 std::vector 和 reserve() 一些字节:

void f(int n) {
    std::vector<char> a;
    a.resize(n);

    /* Code here. */
}

如果您确实想使用 char[n],请编译为 C99 代码而不是 C++ 代码。

如果出于某种原因绝对必须在堆栈上分配数据,请使用 _alloca 或 _malloca/_freea,它们是 MSVC 库等提供的扩展。

于 2008-11-23T04:40:53.437 回答
2

可变长度数组是在 C99 中引入的。它在 gcc 中受支持,但在 msvc 中不受支持。根据 MSVC 团队的一位人士的说法,微软没有计划在他们的 c/C++ 编译器中支持这个功能。他建议在这些情况下使用 std::vector 。

请注意,C99 并不要求在堆栈上分配数组。编译器可以在堆上分配它。但是,gcc 确实在堆栈上分配了数组。

于 2010-01-07T02:42:32.577 回答
1

通常在 C(除了其他人指出的 C99 编译器)和 C++ 中,如果要在堆栈上分配内存,则必须在编译时知道要分配的大小。局部变量是在堆栈上分配的,因此在运行时长度取决于函数参数的数组违反了此规则。Klein 正确地指出,使用“new”运算符是解决此问题的一种方法:


char *a = new char [n];

'a' 仍然是分配在堆栈上的局部变量,但它不是整个数组(具有可变长度),它只是一个指向数组的指针(它总是相同的大小,因此在编译时已知)。数组是在堆上分配的,它通常播放堆栈的对应物——堆栈用于在编译时已知大小的东西,而堆用于在编译时不知道大小的东西。

于 2008-12-31T15:41:41.177 回答
1

使用 avector<>而不是数组是否合理?或者,因为您要替换 a char *, a std::string? 这些确实适用于运行时大小调整,尽管可能有其他原因不使用它们。

于 2010-01-06T22:20:37.673 回答