18

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)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
xxxxxxx
  • 5,037
  • 6
  • 28
  • 26

7 Answers7

28

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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Jack Klein
  • 304
  • 2
  • 2
  • 2
    Yeah, but allocating from the heap, which "new" does, is much different from allocating from the stack which is what the OP is trying to do. (It could be performance-sensitive code he's trying to compile.) – Jim Buck Nov 23 '08 at 04:47
  • Not so much worries about performance for the moment,I thought it was natural to work...but if it's not part of the C++ standard then I understand – xxxxxxx Nov 23 '08 at 04:49
  • Re: _alloca: OP only asked about getting equivalent code working on MSVC and without using new/delete. – Jim Buck Nov 23 '08 at 05:32
  • 3
    `the second is just to use` The use of the word "just" here implies that manually managing dynamic array lifetime is somehow simpler than having a `std::vector` object. This is far from true. – Lightness Races in Orbit Jan 14 '13 at 16:02
10

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);
Jim Buck
  • 20,482
  • 11
  • 57
  • 74
  • Oh so it allocates on stack ! that's marvelous :) Thanks ! – xxxxxxx Nov 23 '08 at 05:06
  • 1
    Note this comment from the alloca manpage: BUGS The alloca function is machine and compiler dependent. On many systems its implementation is buggy. Its use is discouraged. – Nathan Fellman Nov 23 '08 at 06:30
  • Yeah, but it works for sure under MSVC, which is what the OP was trying to get his code working under. I've been using it myself for years. – Jim Buck Nov 23 '08 at 18:48
  • Why is `aloca` not considered good practice? http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice – poitroae Jan 14 '13 at 16:14
5

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.

David Reis
  • 12,701
  • 7
  • 36
  • 42
2

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.

cuteCAT
  • 2,251
  • 4
  • 25
  • 30
2

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.

strager
  • 88,763
  • 26
  • 134
  • 176
  • yes but I don't understand why g++ has no problem with this while MSVC fails – xxxxxxx Nov 23 '08 at 04:42
  • This is wrong since it allocates from the heap. He wants to allocate on the stack which is what the g++ version does. The reason that MSVC doesn't compile the original version is that it is a g++ extension. – Jim Buck Nov 23 '08 at 04:43
  • He can't have it on the stack with MSVC. He can have it on the heap, or have it be constant sized, there is no way to allocate a variably sized array on the stack with MSVC. – Michael Kohne Nov 23 '08 at 04:48
  • Yes you can. See my answer. (Hint: _alloca :) ) – Jim Buck Nov 23 '08 at 04:50
  • @Jim Buck _alloca is the same as using new/delete and this was known to me before I have posted. @strager I have specified that I am sure I am compiling C++ code right from the very beggining(see title of this post). – xxxxxxx Nov 23 '08 at 04:52
  • No, _alloca allocates from the stack (compiles to a single instruction), and new/delete allocates from the heap (expensive operation). If performance doesn't matter, totally go for the cleanest and most portable code, though. – Jim Buck Nov 23 '08 at 04:56
  • @strager yes those functions you mentioned seem to be ok as they are also [mentioned here](http://msdn.microsoft.com/en-us/library/5471dc8s(VS.80).aspx) – xxxxxxx Nov 23 '08 at 05:09
  • i think you have a typo. Didn't you want to use .resize(n) instead of reserve(n) ? – Johannes Schaub - litb Dec 30 '08 at 13:07
  • @litb, I think it could go either way. But you're right -- resize is probably better than reserve. – strager Dec 31 '08 at 07:00
  • To make it as compatible as possible, use .resize(). That means there is an array there, and something like a[2] (assuming n >= 3) is fully meaningful. .reserve() means to allow for a future array of size n. – David Thornley Dec 31 '08 at 15:56
1

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.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
1

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.

Joseph Garvin
  • 20,727
  • 18
  • 94
  • 165