2008-11-23 99 views
17

我有一个简单的函数,其中声明一个数组的大小为 ,具体取决于int参数。依赖于函数参数的C++数组大小导致编译错误

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这项工作,而无需使用新/删除)

回答

29

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

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

在C++中有两种解决方案。第一种方法是使用一个std :: vector的,第二个就是使用操作new []

char *a = new char [n]; 

当我在写我的回答,另外一个贴一个建议,使用_alloca。我强烈建议不要这样做。您只需为特定于编译器的交换另一个非标准,不可移植的方法即可。

9

你从堆栈中分配的方法是G ++的扩展。要做到MSVC下的等价,你需要使用_alloca:

char *a = (char *)_alloca(n); 
+0

哦,所以它分配在堆栈上!这真是奇妙:)谢谢! – xxxxxxx 2008-11-23 05:06:40

+1

请注意来自alloca手册页的这条评论: BUGS alloca函数依赖于机器和编译器。在很多系统上,它的实现是很麻烦的。它的使用是不鼓励的。 – 2008-11-23 06:30:56

+0

是的,但它确实在MSVC下工作,这是OP试图让他的代码工作。多年来我一直在使用它。 – 2008-11-23 18:48:55

2

您可以使用新/删除堆上分配/释放内存。这比使用char [n]更慢,可能更容易出错,但不幸的是,它不是C++标准的一部分。

您可以使用boost的范围数组类来使用new []的异常安全方法。删除[]会在a超出范围时自动调用。

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

    /* Code here. */ 
} 

您还可以使用std ::向量,储备()一些字节:

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

    /* Code here. */ 
} 

如果要使用的char [N],编译为C99代码,而不是C++码。

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

5

您正在使用不是标准的东西。其实它是标准C但不是C++。这太奇怪了!

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

该功能的替代实现将使用由strager发布的new和delete。

1

通常在C(除了C99编译器和其他人指出的那样)和C++之后,如果你想在堆栈上分配内存,你想要在编译时知道你想分配的内存大小。局部变量在堆栈中分配,所以在运行时长度取决于函数参数的数组违反了此规则。克莱因是正确地指出,使用new操作符是解决这个问题的一种方法:

 

char *a = new char [n]; 

“A”仍然是在栈上分配的局部变量,但不是被整个数组(具有可变长度),它只是一个指向数组的指针(它总是相同的大小,因此在编译时已知)。该数组在堆上分配,堆通常用于堆栈的堆栈 - 堆栈用于编译时已知大小的事物,堆是用于在编译时不知道大小的事情。

1

使用vector<>而不是数组是否合理?或者,由于您要更换char *,请拨打std::string?这些可以很好地适应运行时大小,但可能有其他原因不能使用它们。

2

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

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