As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Why this code doesn't compile
#include <stdio.h>
int x=5;
int a[x];
int main()
{
a[0]=5;
printf("%d\n",a[0]);
return 0;
}
When compiled with gcc filename.c -Wall -ansi -pedantic it produces a error
error: variably modified ‘a’ at file scope
However this code compiles although giving warnings but gives correct output:
#include <stdio.h>
int main()
{
int x=5;
int a[x];
a[0]=5;
printf("%d\n",a[0]);
return 0;
}
warning: ISO C90 forbids variable length array ‘a’ [-Wvla]
However if i try to compile this using g++ filename.c -Wall -ansi -pedantic it produces no warnings and gives correct output too
#include <stdio.h>
const int x=5;
int a[x];
int main()
{
a[0]=5;
printf("%d\n",a[0]);
return 0;
}
I am using gcc version 4.7.0
Please explain in detail what's happening ?
In C(unlike C++) const declarations do not produce constant expressions, i.e. in C you can't use a const int object as array size in a non-VLA array declaration.
So,
const int max_foos = 10;
int foos[max_foos];
is valid in C++ but invalid in C. Equivalent C code will be:
#define MAX_FOOS 10
int foos[MAX_FOOS];
Note that:
const in c doesn't mean constant. It means "read only".
Note variable length arrays became a part of the C standard only in C99 prior to that the standard did not allow them though most compilers allowed them as a extension.
The first code snippet doesn't compile because the array subscript needs be a constant which it is not. Also, variable length arrays cannot be declared at global scope.
The second code snippet doesn't compile because variable length arrays were not part of standard prior to c99.
The third snippet compiles because const declarations produce constant expressions in C++ unlike C.
In C only array objects with automatic storage duration can be variable length arrays. Object declared at file scope cannot have automatic storage duration.
In your second code example, c89/c90 does not have variable length arrays and you have to use a c99 compiler to use the feature. If you are using gcc you can select c99 with option -std=c99. Or you can use the last version of c: c11.
C++ does not have variable length arrays.
Variable length arrays are supported only since C99 and they can't be global:
C11, Array Declarators, 6.7.6.2:
If an identifier is declared as having a variably modified type, it
shall be an ordinary identifier (as defined in 6.2.3), have no
linkage, and have either block scope or function prototype scope. If
an identifier is declared to be an object with static or thread
storage duration, it shall not have a variable length array type.
Yes, and ?
Different generations of C and C++ have different rules for what you can use to size an array. In the first case, you are compiling to classic ANSI (C89/90).
C++ allows (constants) to be used as array sizes, as does C99. Note that the "original" C++ ANSI standard is newer than 1990, so it has a lot of the things added in the C99 standard.
Related
This question already has an answer here:
VLAs when compiling a C++ source with g++
(1 answer)
Closed 7 years ago.
I just read a tutorial about dynamic memory in C++ and it states as follows:
...the size of a regular array needs to be a constant expression, and thus its size has to be determined at the moment of designing the program, before it is run...
However, I just ran a program to test this:
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
int y;
cout << "Enter number of elements of array: ";
cin >> y;
int x[y]; // I declared an array using a variable size instead of a constant expression
x[y-1] = 3;
cout << x[y-1];
return 0;
}
...and there were no errors. So is the statement made by the tutorial incorrect or am I misinterpreting it?
No, they're not.
What you're seeing here is a GNU extension called "variable length arrays" (which are still stack-based).
The quotation is correct in the context of the actual C++ language itself.
If you used proper compilation flags (-Wall -Wextra -pedantic) then your compiler would tell you this.
Your program isn't legal C++. The compiler you are using has an extension to allow you to use a non-constant expression as an array size. Here's what my compiler has to say about it:
main.cpp:10:10: warning: variable length arrays are a C99 feature [-Wvla-extension]
int x[y]; // I declared an array using a variable size instead of a constant expression
^
Furthermore, this has nothing to do with dynamic allocations: your array is still stored on the stack just like any other automatically allocated object.
As others have already stated your compiler is using an extension for this.
When declare array like this ->
int arr[100];
C++ allocates it on stack. To create dynamic array in c++, you have to declare it in following way:
int *arr;
arr = new int[n];
Dynamic arrays are allocated using heap.
You used a compiler that has its own language extension that does not C++ compliant. C++ does not allow Variable Length Arrays as in your program However C does allow to define such arrays. So some C++ compilers include this feature of the C Standard in their C++ grammar.
In C++ the declarator of an array is defined the following way
noptr-declarator [ constant-expressionopt] attribute-specifier-seqopt
while in C it is defined according to the following grammar rule
direct-declarator [ type-qualifier-listopt assignment-expressionopt ]
So the language extension of your compiler uses the definition of the array declarator similar to the C definition of the array declarator.
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.
This question already has answers here:
Why can't the size of a static array be made variable?
(4 answers)
Closed 8 years ago.
I am compiling my C code using the gcc compiler
My code is
main()
{
int i;
scanf("%d",&i);
int a[i];
}
... and it executes it without any warning. However, if I use:
main()
{
int i;
scanf("%d",&i);
static int a[i];
}
... I get an error message saying the size of array is not constant.
If execution of program starts at main function it should not give such error.
and if static data is allocated first before start of main(), how is the compiler able to generate such errors during during compile time?
Variables length arrays are not allowed to be static from the draft C99 standard section 6.7.5.2 Array declarators paragraph 2 says (emphasis mine):
An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have
either block scope and no linkage or function prototype scope. If an identifier is declared to be an object with static storage duration, it shall not have a variable length array type.
In C++ variable length arrays are not part of the standard and are a compiler extension but gcc should be be following the C99 rules there as well.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
Improve this question
I read in a lot of books that C is a subset of C++.
Some books say that C is a subset of C++, except for the little details.
What are some cases when code will compile in C, but not C++?
If you compare C89 with C++ then here are a couple of things
No tentative definitions in C++
int n;
int n; // ill-formed: n already defined
int[] and int[N] not compatible (no compatible types in C++)
int a[1];
int (*ap)[] = &a; // ill-formed: a does not have type int[]
No K&R function definition style
int b(a) int a; { } // ill-formed: grammar error
Nested struct has class-scope in C++
struct A { struct B { int a; } b; int c; };
struct B b; // ill-formed: b has incomplete type (*not* A::B)
No default int
auto a; // ill-formed: type-specifier missing
C99 adds a whole lot of other cases
No special handling of declaration specifiers in array dimensions of parameters
// ill-formed: invalid syntax
void f(int p[static 100]) { }
No variable length arrays
// ill-formed: n is not a constant expression
int n = 1;
int an[n];
No flexible array member
// ill-formed: fam has incomplete type
struct A { int a; int fam[]; };
No restrict qualifier for helping aliasing analysis
// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
In C, sizeof('a') is equal to sizeof(int).
In C++, sizeof('a') is equal to sizeof(char).
C++ has new keywords as well. The following is valid C code but won't compile under C++:
int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
There are plenty of things. Just a simple example (it should be enough to prove C is not a proper subset of C++):
int* test = malloc(100 * sizeof(int));
should compile in C but not in C++.
In C++, if you declare a struct, union, or enum, its name is immediately accessible without any qualifiers:
struct foo { ... };
foo x; // declare variable
In C, this won't work, because types thus declared live in their own distinct namespaces. Thus, you have to write:
struct foo { ... };
struct foo x; // declare variable
Notice the presence of struct there on the second line. You have to do the same for union and enum (using their respective keywords), or use the typedef trick:
typedef struct { ... } foo;
foo x; // declare variable
Consequently, you can have several types of different kinds named the same in C, since you can disambiguate:
struct foo { ... };
typedef enum { ... } foo;
struct foo x;
foo y;
In C++, however, while you can prefix a struct name with keyword struct whenever you reference it, the namespaces are merged, and so the above C snippet isn't valid. On the other hand, C++ specifically makes an exception to allow a type and a typedef for that type to have the same name (obviously with no effect), to allow the use of typedef trick unchanged from C.
This also depends on what variety of C you're using. Stroustrup made C++ as compatible as he could, and no more compatible, with the 1989 ANSI and 1990 ISO standards, and the 1995 version changed nothing. The C committee went in a somewhat different direction with the 1999 standard, and the C++ committee has changed the next C++ standard (probably out next year or so) to conform with some of the changes.
Stroustrup lists incompatibilities with C90/C95 in Appendix B.2 of "The C++ Programming Language", Special Edition (which is 3rd edition with some added material):
'a' is an int in C, a char in C++.
The sizeof an enum is int in C, not necessarily in C++.
C++ has // comments to end of line, C doesn't (although it's a common extension).
In C++, a struct foo { definition puts foo into the global namespace, while in C it would have to be referred to as struct foo. This allows a struct definition to shadow a name in an outer scope, and has a few other consequences. Also, C allows larger scope for struct definitions, and allows them in return type and argument type declarations.
C++ is fussier about types in general. It won't allow an integer to be assigned to an enum, and void * objects cannot be assigned to other pointer types without a cast. In C, it's possible to provide an overlarge initializer (char name[5] = "David" where C will discard the trailing null character).
C89 allowed implicit int in many contexts, and C++ doesn't. This means that all functions must be declared in C++, while in C89 it was often possible to get by with assuming int for everything applicable in the function declaration.
In C, it's possible to jump from outside a block to inside using a labeled statement. In C++, this isn't allowed if it skips an initialization.
C is more liberal in external linkage. In C, a global const variable is implicitly extern, and that's not true in C++. C allows a global data object to be declared several times without an extern, but that's not true in C++.
Many C++ keywords are not keywords in C, or are #defined in standard C headers.
There are also some older features of C that aren't considered good style any more. In C, you can declare a function with the argument definitions after the list of arguments. In C, a declaration like int foo() means that foo() can take any number of any type of arguments, while in C++ it's equivalent to int foo(void).
That seems to cover everything from Stroustrup.
If you use gcc, you can use the warning -Wc++-compat to give you warnings about C code which is dubious in C++ in some way. Its currently used in gcc itself, and its gotten a lot better recently (maybe try a nightly version to get the best you can).
(This doesn't strictly answer the question, but folk might like it).
#include <stdio.h>
int new (int n) {
return n/2;
}
int main(void) {
printf("%d\n", new(10));
return 0;
}
See also the C++ FAQ entry.
The single biggest difference I think is that this is a valid C source file:
int main()
{
foo();
}
Note that I haven't declared foo anywhere.
Aside from language differences, C++ also makes some changes to the library that it inherited from C, e.g. some functions return const char * instead of char *.
A number of the answers here cover syntax differences that would cause C++ compilers to fail on C89 (or C99) source code. However, there are some subtle language differences that are legal in both languages but that would produce different behavior. The sizeof (char) difference that Naveen mentioned is one example, but Write a program that will print "C" if compiled as an (ANSI) C program, and "C++" if compiled as a C++ program lists some others.
C compilers generally allowed a little corner cutting that C++ doesn't. C++ is much more strict than C. And generally, some of these differences are compiler-dependant. g++ allows some things that the Intel C++ compiler doesn't, for instance. Even fairly well written C code won't compile with a modern C++ compiler.
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.