Why No Variable Size Array in Stack

Why no variable size array in stack?

Variable Length Arrays(VLA) are not allowed in C++ as per the C++ standard.

Many compilers including gcc support them as a compiler extension, but it is important to note that any code that uses such an extension is non portable.

C++ provides std::vector for implementing a similar functionality as VLA.


There was a proposal to introduce Variable Length Arrays in C++11, but eventually was dropped, because it would need large changes to the type system in C++. The benefit of being able to create small arrays on stack without wasting space or calling constructors for not used elements was considered not significant enough for large changes in C++ type system.

Variable sized array on the stack

They aren't allowed in standard C++, but they are allowed in standard C, and g++ allows them in C++ as well, as a language extension.

How then are variable sized arrays on the stack implemented?

See this question. The gist is that the size (n) gets evaluated and stored in a compiler-generated local variable, and then that much stack space is allocated. There's no law of physics that says the size of a stack variable has to be known at compile-time - it's merely simpler that way.

Why are they even necessary?

They aren't. As you aid, you can do the same thing with dynamic allocation.

Why can't we just use the heap for variable sized buffers?

Stack allocation is more efficient.

Why aren't variable-length arrays part of the C++ standard?

There recently was a discussion about this kicked off in usenet: Why no VLAs in C++0x.

I agree with those people that seem to agree that having to create a potential large array on the stack, which usually has only little space available, isn't good. The argument is, if you know the size beforehand, you can use a static array. And if you don't know the size beforehand, you will write unsafe code.

C99 VLAs could provide a small benefit of being able to create small arrays without wasting space or calling constructors for unused elements, but they will introduce rather large changes to the type system (you need to be able to specify types depending on runtime values - this does not yet exist in current C++, except for new operator type-specifiers, but they are treated specially, so that the runtime-ness doesn't escape the scope of the new operator).

You can use std::vector, but it is not quite the same, as it uses dynamic memory, and making it use one's own stack-allocator isn't exactly easy (alignment is an issue, too). It also doesn't solve the same problem, because a vector is a resizable container, whereas VLAs are fixed-size. The C++ Dynamic Array proposal is intended to introduce a library based solution, as alternative to a language based VLA. However, it's not going to be part of C++0x, as far as I know.

Variable-sized objects on the stack

Is there a way to create a variable-sized class/struct strictly on the stack?

No. There is no support for variable-sized class/struct in the C++ Standard, so they can't be created anywhere. That said, you can create a class/struct in which the final data member is an array, and deliberately overrun the array dimensions. This trick's known as the "struct hack" in C - see the FAQ. Whether it's undefined behaviour depends on your implementation. You can use it in combination with alloca and placement-new to create such a variable on the stack, but should be careful to manually delete it afterwards if your program depends on any side-effects of the destructor.

If not, is this due simply to the specifications or is there an underlying technical reason that it is forbidden?

The reason is performance. Normally, variables on the stack can be accessed using the stack pointer CPU register plus a constant offset, which the compiler can calculate for any given local/automatic variable at compiler time. When you have variable length content on the stack, the local variables after that are no longer at fixed offsets from the stack pointer register, which means the compiler has to generate code to add various values in order to calculate a runtime offset at which to access the variables. When you have several variable-length stack-hosted variables, the problems compound and the performance degrades further. To avoid programmers producing unexpectedly slow code, and to keep compilers simpler, the Standard doesn't require support for variable length types.

Why can't the size of a static array be made variable?

Since the size of the array you declare is not constant, what you have is an Variable Length Array(VLA). VLA are allowed by the c99 standard but there are some limitations associated with it. You cannot have an variable length array with static or extern storage class specifier.

You have an VLA with static storage specification and it is not allowed by the C99 Standard.

Reference:

c99 Standard: 6.7.5.2/8

EXAMPLE 4 All declarations of variably modified (VM) types have to be at either block scope or
function prototype scope. Array objects declared with the static or extern storage class specifier cannot have a variable length array (VLA) type. However, an object declared with the static storage class specifier can have a VM type (that is, a pointer to a VLA type). Finally, all identifiers declared with a VM type have to be ordinary identifiers and cannot, therefore, be members of structures or unions.

So if you want a dynamic size array with static storage specifier you will have to use a dynamic array allocated on heap.

#define MAX_SIZE 256
static int* gArr;
gArr = malloc(MAX_SIZE * sizeof(int));

EDIT:
To answer your updated question:

When you remove the static keyword from the declaration, the storage specifier of the declared array changes from static to global, note the standard quote above, it clearly mentions the restriction that VLAs are not allowed with static and extern storage specification. Clearly, you are allowed to have an VLA with global storage specification, which is what you have once you remove the static keyword.

C: how stack array with variable size works and result is correct? What happened in memory?

I remember that stack array CANNOT assign its size by variable(except const), because variable only know when runtime.

This is false. A static array cannot have a variable length, since its length must be fixed during translation time (compilation time). An automatic array can have a variable length (subject to compiler support), since it is commonly implemented by using the hardware stack, which is designed to support run-time allocations.

However, today, I face this kind of code at work, I use -std=c89, and c99, etc, no any problem.

Support for variable-length arrays was required in C 1999. Compilers earlier than that may have supported it as an extension. It was made an optional feature in later versions of the standard, but compilers that had support previously generally retained it.

This code shall report compiler error.

Are you saying there is a rule that the compiler shall report an error for this? What rule, why do you say that?

I assign 5 values to it, works. I assign 6 values to it, works(No seg fault). I assign 100 values to it, end part(out of range) gets wrong value, remaining still correct.

When you use more elements than have been allocated for an array, the behavior is not defined by the C standard or, generally, but an implementation (except when using debugging or safety features to detect or avoid overruns). Commonly, there is nothing to prevent you from trying to use six or more elements of a five-element array. Doing so may corrupt your program’s memory in various ways. It may appear to work in some circumstances, as long as the overrun does not destroy other data your program needs to appear to work.

I am not sure 1. Why this can compile? gcc changed?

It compiled because the compiler supported variable length arrays.


  1. Why this work? Stack array is not allocated at runtime time, its size is fixed, why this "pseudo-dynamic" array works?

Stack arrays are generally allocated at run time.

How does GCC create an array on the stack without its size being given by a constant variable?

My understanding is that since the input's value is not known during compile time, it'd have to be a heap allocated array.

While the C++ language rules do indeed say that you can’t do this, from a technical perspective about how the call stack is typically implemented this actually isn’t necessarily true. Generally, yes, objects that don’t have a size known in advance aren’t put on the stack. However, in the case of a local variable that’s an array of variable length, it’s not that hard for the compiler to put that array in stack space. For example, the C language supports this, and this older question addresses one way of implementing it. Even though C++ doesn’t allow for variable-length arrays the way C does (technically speaking what you have here isn’t legal C++ code), some compilers allow for it.

Isn't the stack space for things like arrays (without allocating on the heap) allocated when the program starts?

This usually isn’t the case. When the program starts up, it’s allocated a region of memory and told “this is where your stack should go,” but that space is typically not determined by anything about how the program is written and is usually controlled by the OS or set by the compiler. Then, whenever space on the stack is needed - say, because a function is called or because a new block scope is entered - the program takes up some space on the call stack, handing it back when the block scope exits or the function returns.

As a result, the program doesn’t need to know at the point where it starts how much space to reserve on the stack for each function. It can defer that until the actual functions are called.

why can C++ fill initialize a variable-sized array?

VLA are not part of C++. They are supported by some compilers as an extension. They come from C99, and in C99 you cannot initialize VLA with = {0};. Some compilers (like GCC) go further and add support for such an initialization. In GCC this syntax can be used starting from version 4.9. Clang apparently doesn't support it, and it doesn't have to.

g++ variable size array no warning?

ISO C++ disallows the use of variable length arrays, which g++ happily tells you if you increase the strictness of it by passing it the -pedantic flag.

Using -pedantic will issue a warning about things breaking the standard. If you want g++ to issue an error and with this refuse compilation because of such things; use -pedantic-errors.


g++ -Wall -pedantic -std=c++11 apa.cpp


apa.cpp: In function ‘int main(int, char**)’:
apa.cpp:8:13: warning: ISO C++ forbids variable length array ‘ints’ [-Wvla]
int ints[a];
^
apa.cpp:8:7: warning: unused variable ‘ints’ [-Wunused-variable]
int ints[a];
^


Related Topics



Leave a reply



Submit