C++ array size dependent on function parameter cau

2019-01-11 23:19发布

问题:

I have a simple function in which an array is declared with size depending on the parameter which is int.

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

    int main() {
        return 0;
    }

This piece of code compiles fine on GNU C++, but not on MSVC 2005.

I get the following compilation errors:

    .\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

What can I do to correct this?

(I'm interested in making this work with MSVC,without using new/delete)

回答1:

What you have found it one of the Gnu compiler's extensions to the C++ language. In this case, Visual C++ is completely correct. Arrays in C++ must be defined with a size that is a compile-time constant expression.

There was a feature added to C in the 1999 update to that language called variable length arrays, where this is legal. If you can find a C compiler that supports C99, which is not easy. But this feature is not part of standard C++, not is it going to be added in the next update to the C++ standard.

There are two solutions in C++. The first is to use a std::vector, the second is just to use operator new []:

char *a = new char [n];

While I was writing my answer, another one posted a suggestion to use _alloca. I would strongly recommend against that. You would just be exchanging one non-standard, non-portable method for another one just as compiler-specific.



回答2:

Your method of allocating from the stack is a g++ extension. To do the equivalent under MSVC, you need to use _alloca:

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


回答3:

You are using something that is not a standard. Actually it is standard C but not C++. How peculiar is that!

Explaining a bit more, run time sized stack arrays are not part of C++, but are part of C99, the latest standard for C. That´s why some compilers will get it, while others will not. I would recommend refrain from using it, to avoid compiler compatibility issues.

The alternate implementation of the functionality would be using new and delete, as posted by strager.



回答4:

You can use new/delete to allocate/free memory on the heap. This is slower and possibly more error prone than using char[n], but it's not part of the C++ standard yet, sadly.

You can used boost's scoped array class for an exception-safe method for using new[]. delete[] is automatically called on a when it goes out of scope.

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

    /* Code here. */
}

You can also use std::vector, and reserve() some bytes:

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

    /* Code here. */
}

If you do want to use char[n], compile as C99 code instead of C++ code.

If you absolutely must allocate data on the stack for some reason, use _alloca or _malloca/_freea, which are extensions provided by MSVC libs and such.



回答5:

variable length array was introduced in C99. It is supported in gcc but not msvc. According to a person in MSVC team, Microsoft has no plan to support this feature in their c/C++ compiler. He suggested to use std::vector in those cases.

Note that C99 does not require that the array allocated on the stack. The compiler can allocate it on the heap. However, gcc does allocate the array on the stack.



回答6:

Typically in C (excepting C99 compilers as others have pointed out) and C++, if you want to allocate memory on the stack, the size of what you want to allocate has to be known at compile time. Local variables are allocated on the stack, so an array whose length depends on a function parameter at run time violates this rule. Klein is correct to point out that using the 'new' operator is one way to solve this problem:


char *a = new char [n];

'a' is still a local variable allocated on the stack, but instead of being the whole array (which has variable length), it's just a pointer to an array (which is always the same size, and thus known at compile time). The array is allocated on the heap, which typically plays the stack's counterpart -- the stack is for things with a size known at compile time, and the heap is for things with a size not known at a compile time.



回答7:

Would it be reasonable to use a vector<> rather than an array? Or, since you're replacing a char *, a std::string? Those do work well with runtime sizing, although there may be other reasons not to use them.