5

According to this answer, which states:

The compiler knows the size of the int type and therefore can generate the right assembler instruction that will reserve enough space on the stack in order to let foo live there.

a compiler needs to know the size a function will occupy on the stack in order to implement it.

Then, why does this code compile?

int f(int n)
{
    int x[n];
}

int main()
{
    f(3);
    f(5);
    //etc
}

x is an array of integers, but its size isn't constant, it can change any time the function is called.

What am I missing here?

Community
  • 1
  • 1
corazza
  • 31,222
  • 37
  • 115
  • 186
  • 5
    Compile it again with `-pedantic`. – chris Apr 08 '13 at 19:39
  • 1
    "erw.cpp: In function ‘int f(int)’: erw.cpp:3:12: warning: ISO C++ forbids variable length array ‘x’ [-Wvla]" - @chris: thanks, this makes sense now. – corazza Apr 08 '13 at 19:40
  • possible duplicate of [In C++ books, array bound must be constant expression, but why the following code works?](http://stackoverflow.com/questions/5947661/in-c-books-array-bound-must-be-constant-expression-but-why-the-following-cod) – Bo Persson Apr 08 '13 at 19:58
  • Allocating space for x on stack is just a matter of subtracting sizeof(int)*n from esp (stack pointer). Semantics is the problem - like in the case of initializing an enum {Ok = sizeof(x)}. May be until a prohibiting semantic usage appears your compiler is allowing such usage. – nanda Apr 08 '13 at 19:58
  • I changed the language tag to [C99], to match the actual code. It's indeed not legal in C++, but the question remains how a compiler can do this. – MSalters Apr 08 '13 at 20:15
  • @MSalters: bad move, IMHO. Two of the answers are making use of specific C++ features: the stl vector and templates in general. Would you agree that I should retag the question back to C++ again? – corazza Apr 08 '13 at 21:19
  • 1
    @MSalters: Sorry, rolled back. The question was about C++, not C99, and Luchian Grigore's answer as well as mine targeted that kind of question ("Why am I allowed to do this, why does it compile at all? Isn't this illegal?"). Although the question "How does the compiler manage to realize VLAs" is also interesting, that's not what was originally meant by the OP. – Andy Prowl Apr 08 '13 at 21:29
  • Well, vote to close then. The VLA-in-C++ extension question was already answered in http://stackoverflow.com/questions/5947661/in-c-books-array-bound-must-be-constant-expression-but-why-the-following-cod. – MSalters Apr 08 '13 at 23:33

3 Answers3

8

This is not legal code in Standard C++. It compiles thanks to an extension specific to your compiler which supports variable-length arrays, which is a C99 feature.

But again, this is not portable C++. If you need dynamic sizing, you could rewrite your function this way:

#include <vector>

int f(int n)
{
    std::vector<int> v(n);
}

Otherwise, make it a template and write it this way:

#include <array>

template<std::size_t N>
int f()
{
    std::array<int, N> a;
}
Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
4

It compiles because you're using a non-standard extension. In the strict sense, it's not valid C++, but some compilers do support this.

In your case (3 and 5 are known), you can use templates instead, which would be valid, or directly a std::vector.

template<int n>
int f()
{
    int x[n];
}

//...
f<3>();
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

The compiler's job is indeed harder in this case. It now needs to emit code which will - at runtime - figure out how much memory is needed (n*sizeof(int)), and where to get that memory from. That memory is still released at the same place as where int y[5]; would be released, so in that respect nothing changes.

One easy solution for the compiler is to change the code behind the scenes to int * __x = malloc(n*sizeof(int) ... free(__x). It might also need to rewrite some code for sizeof(x), but there too the compiler can rewrite the VLA code to "normal" code. There is no magic needed; VLA's can be implemented as mere syntactic sugar.

MSalters
  • 173,980
  • 10
  • 155
  • 350