I have some concepts about the VLA and its behavior that I need to clarify.
AFIK since C99 it's possible to declare VLA into local scopes:
int main(int argc, char **argv)
{
// function 'main' scope
int size = 100;
int array[size];
return 0;
}
But it is forbidden in global scopes:
const int global_size = 100;
int global_array[global_size]; // forbidden in C99, allowed in C++
int main(int argc, char **argv)
{
int local_size = 100;
int local_array[local_size];
return 0;
}
The code above declares a VLA in C99 because the const modifier doesn't create a compile-time value. In C++ global_size is a compile-time value so, global_array doesn't become a VLA.
What I need to know is: Is my reasoning correct? Is the behaviour that I've described correct?
I also want to know: Why are the VLA not allowed in global scope? are they forbidden both in C and C++? Why is the behavior of arrays into global and local scope different?
Yes your reasoning is correct, that is how these different forms of array declarations and definitions are viewed by C and C++.
As others already stated, VLA with a veritable variable length (non-const) in global scope is difficult to make sense. What would the evaluation order be, e.g if the the length expression would refer to an object of a different compilation unit? C++ doesn't have VLA, but it has dynamic initialization of objects at file scope. And already this gives you quite a head ache, if you have to rely on evaluation order.
This leaves the small gap for C concerning length expressions that contain a const qualified object, which isn't allowed. This comes from the fact that such objects are not considered "integer constant expressions" by the C standard. This could perhaps change in future versions, but up to now the C committee didn't find it necessary to allow for such a thing: there are enum constants that play that role in C. Their only limitation is that they are limited to int in C, it would be nice to also have them size_t.
C++ doesn't support VLAs, period. The reason the second code snippet works in C++ is that the const keyword creates a compile-time constant in C++; in C, it doesn't.
C99 doesn't support VLAs outside of block scope, period, regardless of how you declare the size variable. Note that C2011 makes VLA support optional.
There is a difference between being forbidden and not being allowed. ;-)
The VLA feature is designed to allow the use of stack space for a local array, to avoid the use of malloc for heap allocation. It is mostly a speed optimization.
Now you want to use VLAs outside of functions. Why? There is not much to win speedwise in avoiding a single malloc call during program start. And what stack space are we supposed to use for variables with a static life time?
I think the fundamental reason is a global variable has linkage, its size has to be known at compile time. If not, how could one link the program?
local variables have no linkage and the VLAs are allocated on the stack, which grows dynamically as the program runs.
So, for global VLA's, one of the issues (there are many variants on the theme) can be shown here:
int size;
int a;
int v[size];
int b;
....
in another file:
extern int a;
extern int b;
The linker will have to know where a and be are in relation to each other at link time, or it won't be able to fix them up correctly at load-time.
Related
Why can't we initialize array size using non-const size in global area....outside main() ....
//outside main - global
int val=5;
int arr[val];
int main()
{
}
this gives error
7:12: error: array bound is not an integer constant before ']' token
In function 'int main()':
But if i move this same code inside main/body of function error disappears....
there is no error and it compiles fine...
int main()
{
int val=5;
int arr[val];
}
Also this works fine inside body of a function
void fn(int val)
{
int arr[val];
}
int main()
{
fn(5);
}
Confused and how does moving array size can't be intialized only outside main?
The first sample, at file scope
int val=5;
int arr[val];
int main()
is illegal on both C and C++. Variables at file scope must be defined (created) before their first use, and continue to exist until the program ends - which also means that, once created, an array cannot be resized. In the case of arrays, this means (among other things) that their dimension must be known at compile time. Using a variable as an array dimension runs afoul of the need for the size of a static to be known at compile time - for example, the value of val could be changed at run time (e.g. in main()) which will be AFTER arr is created.
The second example
void fn(int val)
{
int arr[val];
}
is legal in C (from 1999), because arr is of automatic (not static) storage duration. It will be created when the function body is entered, and cease to exist when the function returns. This is called a "variable length array" or VLA, because the number of elements is determined by a value of a variable (val) at run time.
VLAs were also not supported before the 1999 C standard.
In C++, VLAs are illegal. Period. However, some C++ compilers do support such a feature as a non-standard extension. In C++, rather than using arrays, a standard container (e.g. std::vector<int>) is preferred for various reasons, including ability to resize it at run time.
For the array inside function:
you are relying on GCC extension, if you add -pedantic you will get this warning:
warning: ISO C++ forbids variable length array 'arr' [-Wvla]
So C++ does not support variable length arrays, suggested alternative is std::vector.
For the array outside function:
you need to add const before int. Yes I know compiler could in theory figure out that val is never changed, but for some reason(nobody thought to add that to standard, or there are good reasons not to do it) you are required to add const.
This question already has answers here:
Why aren't variable-length arrays part of the C++ standard?
(10 answers)
Closed 8 years ago.
The code compiles and runs, but is it legal? AFAIK, size of static array must be known at compile time.
#include <iostream>
void foo(const unsigned size){
double arr[size];
for(auto& i:arr){
i=2;
std::cout << i;
}
}
int main(){
unsigned size;
std::cin >> size;
foo(size);
}
Strictly speaking, this is not legal. Variable length arrays (VLA) are not supported by standard C++. VLA are supported by most compilers an an extension but using those may give you non portable behavior.
Also, there is no static array in your source code. To do so you would need to use the static keyword on the declaration.
As user657267 mentioned, Runtime-size arrays have been discussed for C++14 in N3639 and another similar feature, std::dynarray has been discussed, however they have been rejected for C++14.
Currently, this is not considered as part of the standard although some compilers implemented this as non-portable extensions, gcc for example is one of these compilers (possibly because this is legal in C99).
Most of the time, you can just use a vector to the same effect.
In your example there is no array with the static storage duration. There is a local array within a function with automatic storage duration.
The size of the array shall be a constant expression.
If the code you showed is compiled then it means it is a feature of the compiler that supports Variable Length Arrays in C++ the same way as in C.
I am new to C++.I was going through a C++ book and it says
const int i[] = { 1, 2, 3, 4 };
float f[i[3]]; // Illegal
It says the declaration of the float variable is invalid during compilation.Why is that?
Suppose if we use
int i = 3;
float f[i];
It works.
What is the problem with the first situation?
Thanks.
So the first is illegal because an array must have a compile-time known bound, and i[3], while strictly speaking known at compile time, does not fulfill the criteria the language sets for "compile-time known".
The second is also illegal for the same reason.
Both cases, however, will generally be accepted by GCC because it supports C99-style runtime-sized arrays as an extension in C++. Pass the -pedantic flag to GCC to make it complain.
Edit: The C++ standard term is "integral constant expression", and things qualifying as such are described in detail in section 5.19 of the standard. The exact rules are non-trivial and C++11 has a much wider range of things that qualify due to constexpr, but in C++98, the list of legal things is, roughly:
integer literals
simple expressions involving only constants
non-type template parameters of integral type
variables of integral type declared as const and initialized with a constant expression
Your second example doesn't work and it shouldn't work.
i must be constant. This works
const int i = 3;
float f[i];
Just to expound on Sebastian's answer:
When you create a static array, the compiler must know how much space it needs to reserve. That means the array size must be known at compile-time. In other words, it must be a literal or a constant:
const int SIZE = 3;
int arr[SIZE]; // ok
int arr[3]; // also ok
int size = 3;
int arr[size]; // Not OK
Since the value of size could be different by the time the array is created, the oompiler won't know how much space to reserve for the array. If you declare it as const, it knows the value will not change, and can reserve the proper amount of space.
If you need an array of a variable size, you will need to create it dynamically using new (and make sure to clean it up with delete when you are done with it).
For arrays with lengths known only at runtime in C++ we have std::vector<T>. For builtin arrays the size must be known at compile-time. This is also true for C++11, although the much older C99-standard already supports dynamic stack arrays. See also the accepted answer of Why doesn't C++ support dynamic arrays on the stack?
This question may be naive, but:
is there const keyword in C?
since which version?
are there any semantic and/or syntactic differences between const in C and C++?
There are no syntactic differences between C and C++ with regard to const keyword, besides a rather obscure one: in C (since C99) you can declare function parameters as
void foo(int a[const]);
which is equivalent to
void foo(int *const a);
declaration. C++ does not support such syntax.
Semantic differences exist as well. As #Ben Voigt already noted, in C const declarations do not produce constant expressions, i.e. in C you can't use a const int object in a case label, as a bit-field width or as array size in a non-VLA array declaration (all this is possible in C++). Also, const objects have external linkage by default in C (internal linkage in C++).
There's at least one more semantic difference, which Ben did not mention. Const-correctness rules of C++ language support the following standard conversion
int **pp = 0;
const int *const *cpp = pp; // OK in C++
int ***ppp = 0;
int *const *const *cppp = ppp; // OK in C++
These initializations are illegal in C.
int **pp = 0;
const int *const *cpp = pp; /* ERROR in C */
int ***ppp = 0;
int *const *const *cppp = ppp; /* ERROR in C */
Generally, when dealing with multi-level pointers, C++ says that you can add const-qualification at any depth of indirection, as long as you also add const-qualification all the way to the top level.
In C you can only add const-qualification to the type pointed by the top-level pointer, but no deeper.
int **pp = 0;
int *const *cpp = pp; /* OK in C */
int ***ppp = 0;
int **const *cppp = ppp; /* OK in C */
Another manifestation of the same underlying general principle is the way const-correctness rules work with arrays in C and C++. In C++ you can do
int a[10];
const int (*p)[10] = &a; // OK in C++
Trying to do the same in C will result in an error
int a[10];
const int (*p)[10] = &a; /* ERROR in C */
The first two questions are answered here: Const in C
Yes there are quite a few differences in semantics between const in C and C++.
In C++, const variables of appropriate type are integral constant expressions (if their initializers are compile-time constant expressions) and can be used in context which requires that, such as array bounds, and in enum definitions. In C, they are not and cannot be.
In C++, const global variables automatically have static linkage, so you can put them in header files. In C, such variables have external linkage and that would generate duplicate definition errors at link time.
Yes, there is a const keyword. It was added as part of the 1989 standard.
As far as compatibility, here's a paragraph from Harbison & Steele, 5th edition:
A top-level declaration that has the type qualifier const but no explicit storage class is considered to be static in C++ but extern in C. To remain compatible, examine top-level const declarations and provide an explicit storage class.
In C++, string constants are implicitly const; they are not in C.
Yes, const has been there since at least since ANSI C (aka C89).
It certainly appears in my copy of "The C Programming Language (2nd Edition)", Kernighan & Ritchie (published in 1988).
Relevant extract:
The const and volatile properties are new with the ANSI standard. The purpose of const is to
announce objects that may be placed in read-only memory, and perhaps to increase opportunities for
optimization.
Two other differences:
const arraytype (i.e typedef int A[1]; const A a = { 0 };) specifies a constant array type ( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112 and http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1059 ) (and whose elements are so-qualified too) in C++, but a non-constant array type whose elements are so-qualified in C.
const const is valid in C99 (not valid in C89), not valid in C++ in any version (you can only semantically repeat a const, not syntactically). It contracts to const in C99.
Yes. const is there in C, from C89.
Here is a good read is about behaviour of const keyword in C.
The semantic in C is different than in C++. For example,
unsigned const a = 10;
unsigned A[a];
in file scope would be valid in C++, but not in C.
Yes, there's a const keyword in C. It's been there since C90.
Syntactically, it can occur in the same places as in C++. Semantically, it's a bit more lax, IIRC.
According to ESR, const was added in the ANSI C Draft Proposed Standard. Eric Giguere's summary of ANSI C, dated 1987, confirms it.
This looks like the draft itself -- search for "3.5.3 Type qualifiers".
There is a "const" keyword in C, and it has been for a long time. If a variable is designated "const", writes to it are forbidden.
Additionally, in some environments, variables declared "const" may be located in a different data segment from other variables. This data segment may offer hardware write protection, and for embedded systems, may be stored in ROM or flash memory rather than in RAM (a very important distinction on some processors which have a lot more ROM or flash than RAM--e.g. 128 KB flash and 3.5 KB RAM, or 2 KB ROM and 96 bytes RAM).
Note that the compiler will generally not make any inferences about "const" values or expressions involving them. If I say "const char foo[] = "Hello";" and then later make reference to foo[1], the compiler will load the value (which will most likely be 'e') from wherever foo[] is stored and use the loaded value. Sometimes this usefully allows values to be patched in a compiled code image, but sometimes it just wastes code.
If you want to define a number to to be a compile-time "substitutable" constant, the best way, at least for integer constants, may be to use "enum". For example, "enum {woozle=19;}" will cause 19 to be substituted for "woozle" throughout the code. Note that unlike textual substitutions; enum declarations obey proper rules of scope.
Why this dont work:
int size = 2;
int array[size];
int main() {
return 0;
}
It says the error: array bound is not an integer constant
And this work:
int size = 2;
int main() {
int array[size];
return 0;
}
Anyone knows the reason?
thanks
In C++ or C89/90 neither works. These languages require that array size is an Integral Constant Expression (ICE). In your examples size is not an ICE. If your C++ or C89/90 compiler allows it, it is nothing else than a non-standard compiler extension.
In C99 the second works because this is how Variable Array Length (VLA) specification is defined. VLA can only be defined in local scope.
Dynamic sized arrays is a feature of C99 and is not included in the current C++ standard at all.
If you are compiling as C++ neither should work. If you change to a const variable then both methods will be allowed by the C++ standard.