No, wait, bear with me...
VLAs were always a GCC extension, but they were adopted by C99:
[C99: 6.7.5.2/4]: If the size is not present, the array type is an
incomplete type. If the size is * instead of being an expression, the
array type is a variable length array type of unspecified size, which
can only be used in declarations with function prototype scope; such
arrays are nonetheless complete types. If the size is an integer
constant expression and the element type has a known constant size,
the array type is not a variable length array type; otherwise, the
array type is a variable length array type.
C99 is also known as ISO/IEC 9899:1999.
Now:
[C++11: 1.1/2]: C++ is a general purpose programming language based
on the C programming language as specified in ISO/IEC 9899:1999
(hereinafter referred to as the C standard). In addition to the
facilities provided by C, C++ provides additional data types, classes,
templates, exceptions, namespaces, operator overloading, function name
overloading, references, free store management operators, and
additional library facilities.
So shouldn't C++11 have VLAs too?
That leeway wording doesn't mean that any and everything in C99 is in C++11. What you quoted is just introductory text.
This C99 feature is effectively overridden by C++'s own semantics, as can be any otherwise "inherited" feature:
[C++11: 8.3.4/1]: In a declaration T D where D has the form
D1 [ constant-expressionopt ] attribute-specifier-seqopt
[..]
This is the only array declaration syntax we're given in C++.
Note that no mention of this difference is given in the "compatibility with C" clause C.1.
The definition of constant-expression is different for the two languages.
const size_t size = 5;
int array[size]; // array in C++, VLA in C
This compiles for me: (g++ 4.6 with -std=c++0x). But it doesn't compile with -pedantic (thanks #MarkB). Instead it warns that "template.cpp:7:12: warning: ISO C++ forbids variable length array ‘n’ [-Wvla]"
int main(int argc, char ** argv) {
int n[argc];
}
So the size of n can not be known at compile time by the compiler. Is this a GNU extension to C++? This does appear to be a GNU extension, and that VLAs are not an official part of C++11.
(Of course, I'm just playing with a compiler. So take this with a pinch of salt.)
Related
The following code compiles under gcc 4.8 and Clang 3.2:
int main()
{
int size = 10;
int arr[size];
}
8.3.4/1 of the C++ Standard says that the size of an array must be an integral constant expression, which size does not seem to be. Is this a bug in both compilers, or am I missing something?
The latest VC++ CTP rejects the code with this interesting message:
error C2466: cannot allocate an array of constant size 0
The interesting part is how it seems to think that size is zero. But at least it rejects the code. Shouldn't gcc and Clang do the same?
This is variable length arrays or VLA which is a C99 feature but gcc and clang support it as an extension in C++ while Visual Studio does not. So Visual Studio is adhering to the standard in this case and is technically correct. Not to say that extensions are bad, the Linux kernel depends on many gcc extensions, so they can be useful in certain contexts.
If you add the -pedantic flag both gcc and clang will warn you about this, for example gcc says (see it live):
warning: ISO C++ forbids variable length array 'arr' [-Wvla]
int arr[size];
^
Using the -pedantic-errors flag will make this an error. You can read more about extensions in these documents Language Standards Supported by GCC and clangs Language Compatibility section.
Update
The draft C++ standard covers what is a integral constant expression in section 5.19 Constant expressions paragraph 3 and says:
An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [...]
It is not intuitively obvious from reading this what all the possibilities are but Boost's Coding Guidelines for Integral Constant Expressions does a great job of that .
In this case since you are initializing size with a literal using const would suffice to make it an integral constant expression (see [expr.const]p2.9.1) and also bring the code back to being standard C++:
const int size = 10;
using constexpr would work too:
constexpr int size = 10;
It would probably help to read Difference between constexpr and const.
For reference the equivalent section to 8.3.4 paragraph 1 in the C99 draft standard would be section 6.7.5.2 Array declarators paragraph 4 which says (emphasis mine):
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope;124) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
I thought I should get compile error for the following char array definition of the allData:
void MyClass::aMethod(const char* data, int size)
{
int headerSize = 50;
MyHeader header;
//size is not constant and unknown at compile time
char allData[size + headerSize]; //<<<<<==== should not allowed!! but not error??
memcpy(allData, &header, headerSize);
memcpy(allData + headerSize, data, size);
....
}
Why? It will give a run-time error?
Both gcc and clang and possibly others although not visual C++, supports variable length arrays an extension even though it is a C99 feature not a C++ feature.
In both gcc and clang if you compile with -pedantic they will warn you that you are using extensions, for example gcc would produce a similar warning to this:
warning: ISO C++ forbids variable length array ‘allData’ [-Wvla]
and you can use -pedantic-errors to turn the warning into an error.
As far as I understand C++14 may support variable length arrays. The C99 draft standard section 6.7.5.2 Array declarators says:
[...] If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
while the C++ draft standard requires a constant, the draft C++ standard in section 8.3.4 Arrays says:
In a declaration T D where D has the form
D1 [ constant-expressionopt] attribute-specifier-seqopt
[..] If the constant-expression (5.19) is present, it shall be a converted constant expression of type std::size_t and its value shall be greater than zero. [...]
Some C++ compilers have an option that allows to use C VLA in C++.
Why this type of declaration
int nArraySize = 7;
char szName[nArraySize] = "Mollie";
returns this error:
error: variable-sized object 'szName' may not be initialized
but when I declare the 'arraySize' variable as a 'const int' it works ?
const int nArraySize = 7;
char szName[nArraySize] = "Mollie";
It must be said first that in C++ language, the size part of array declaration is required to be an Integral Constant Expression (ICE). A const int object declared with an initializer can be used in an ICE. An int object cannot be used in an ICE. That's the formal part of it.
However, judging by the error message, your C++ compiler supports C99-style variable-length arrays (VLA) in C++, as a non-standard extension. That means that in your compiler you are allowed to use non-constant expressions to specify size in array declarations. Yet even if VLAs themselves are supported, such arrays still cannot be initialized. This is prohibited by the specification of VLAs in C99, and that is exactly how their specification is "inherited" by your C++ compiler.
In other words, contrary to what other answers stated, this code will probably be accepted by your C++ compiler
int nArraySize = 7;
char szName[nArraySize];
even though it is formally illegal C++. It is the = "Mollie" part that triggers the error.
Because C++ does not support variable-length arrays (introduced in the C-99 standard, but not in any version of C++). When you declare nArraySize as a non const int, the compiler complains because nArraySize may change at runtime. If nArraySize is const, the compiler knows that it cannot change at runtime, and therefore the array size of szName cannot be variable (i.e. can be deduced at compile time). In C++ (and versions of C before C99), the size of an array must be a constant that can be deduced at compile-time.
Because the program has to know at compile time how much memory to alocate for your variables. When you don't make your nArraySize constant it is assumed it may change during runtime. While making it constant asures the compiler this value will not be changed.
The first is a variable length array and it's standardized in C (since the C99 standard) but not in C++.
C++ needs all arrays to have their sizes available at compile time, not runtime. Declaring the size as a constant makes it a compile-time constant.
The Standard does not permit dynamically-sized, statically-allocated arrays. You may find that in GCC you will be able to do this, but that is because that is one of a number of extensions that allow non-conforming behavior.
An array is defined like this:
D1 [ constant-expressionopt] attribute-specifier-seqopt
Where the size is an integral constant expression. The Standard defines an integral constant expression like this:
An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [Note: Such expressions
may be used as array bounds (8.3.4, 5.3.4), [...] — end note]
int n = 10;
int x[n]; // error!
The variable n is not a constant expression, so it will not work for this case.
By adding constexpr (C++11) to the type, it will be useable in a constant expression. But in this case const is enough to make it work:
int const n = 5;
int x[n];
On the other hand, dynamic arrays take a dynamic size specifier:
int n = 10;
int *x = new int[n];
But an option I would recommend using is std::vector which is a wrapper around a dynamically-sized buffer:
#include <vector>
int main()
{
int n = 10;
std::vector<int> x(n); // x.size() is 10
}
I hope this helped.
GCC gives no error when you initialize a variable-sized array as long as the variable is const, but when it isn't, it won't compile.
What's the reason behind this? What's so wrong with doing:
int size = 7;
int test[size] = {3, 4, 5};
That won't compile at all, but if I don't initialize test[] then it does compile! That doesn't make any sense to me, because as far as I know a stack frame needs to be made to fit this array according to its size(7 ints) no matter what(which means the integer literals I use don't really have any meaning, if I'm not mistaken), so what difference does it make if I initialize it or not?
Just another one of my crazy C++ design questions...
Thanks!
The size of the array must be a constant integral expression.
An integral literal is a constant integral expression. (int arr[5];)
A constant integral variable initialized with a constant expression is a constant expression. (const int j = 4; const int i = j; int a[i];)
A constant variable initialized with a non-constant expression is not a constant expression
int x = 4; // x isn't constant expression because it is not const
const int y = x; //therefore y is not either
int arr[y]; //error)
It's actually more like a crazy C99 design question, since variable-length arrays are a feature from C99 that gcc allows in C++ as an extension.
In C99, 6.7.8/3 says "The type of the entity to be initialized ... is not a variable length array type", so gcc has just used the same rule for its extension as is required by C99.
The C99 rationale document doesn't say anything about why a VLA can't be initialized. I can speculate that it might be because of the risk of excess elements in the initializer, if the value provided for the size turns out to be smaller than the initializer. But I don't know.
Some compilers allow this if you use const int size = 7;. Theoretically the compiler could figure out that it's constant size but it doesn't do that.
From http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html "Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C90 mode and in C++. "
Your program is not valid in c++ at all and gcc compiles it as "an extension". You'd likely have to ask the authors of gcc why they decided to implement in this way.
The code is not valid in standard C++.
As per (8.3.4.1) of the C++ standard, array size must be a constant expression
Variable lenght arrays are not allowed in C++ because C++ provides std::vector for that.
Variable length array was a feature introduced in C99 after C++ branched out from C standard based on c98. C++ already had std::vector to provide functionality of variable lenght arrays so C++ standard never allowed variable length arrays as a part of the standard.
If your compiler supports it, it is through a compiler extension. Compile with -pedantic option and it will notify you of the same with the warning saying it's forbidden by ISO C++
I'm not sure about the intentions of gcc designers when they implemented this extension, but one possible reason why the gcc extension works like this is:
int is1[2] = {1}
compiles without warning, reasonable to assume user wants {1,0}
int is2[1] = {1,2};
compiles with a warning, what should the compiler do?
int i;
cin >> i;
int is3[i] = {1,2}
aha, to warn or not to warn?
C++ ANSI ISO IEC 14882 2003 Annex C.1 (page 668):
Change: The result of a conditional expression, an assignment expression, or a comma expression may bean lvalue
Rationale: C + + is an object-oriented language, placing relatively more emphasis on lvalues. For example, functions may return lvalues.
Effect on original feature: Change to semantics of well-defined feature. Some C expressions that implicitly rely on lvalue-to-rvalue conversions will yield different results. For example,
char arr[100];
sizeof(0, arr)
yields 100 in C + + and sizeof(char*) in C.
...
I was reading this just today and I remembered that a couple of months a go a friend of mine proposed a problem wchich was to write a function that would return 0 if it were compiled with C++ and 1 if it were compiled with C. I solved it taking advantage of the fact that in C a struct was in the outer scope. So, considering this new information, I decided that this would be another solution to the above problem, which I tried on Microsoft Visual Studio 2008, but regardless of whether it is compiled as C or C++ code sizeof(0, arr) always yields 4. So 2 questions:
1.What is ISO C? Is it the current C standard? Is it the only one (I hear C is rapidly evolving)
2. Is this a microsoft C++ bug?
TIA
Edit: Sorry got mixed up with the output and edited it:
ISO C is the C standard. The current one is C99 but C1x is right around the corner. If by rapid, you mean a new standard every decade or so, then yes, it is rapidly evolving :-)
Section 6.5.3.4/3 of ISO C99 states:
When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.
When applied to an operand that has array type, the result is the total number of bytes in the array.
Or just microsoft's C is not ISO C but some other standard C (if there exists any).
Microsoft Visual C still supports C89 [only] whereas other compilers like gcc/clang etc support C99 too which is the current Standard.
C99 [Section 6.5.17/2] says
The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.95
Thus the result of sizeof (0,arr) would be sizeof(char*)[due to the implicit lvalue to rvalue conversion /automatic decay to pointer type] not 100*sizeof(char)
sizeof(arr) would have given 100*sizeof(char) from 6.5.3.4/3
95) A comma operator does not yield an lvalue.
decided that this would be another solution to the above problem, which I tried on Microsoft Visual Studio 2008, but regardless of whether it is compiled as C or C++ code sizeof(0, arr) always yields 4.
C++03 [5.18/1] Comma Operator
The type and
value of the result are the type and value of the right operand; the result is an lvalue if its right operand is.
So sizeof(0, arr) = sizeof (arr) and which would be equal to 100* sizeof(char) and not = sizeof(char*).
So MSVC++ is giving incorrect result (in case of C++ code).
For arrays, the sizeof returns the total size. Be careful about arrays passed as pointers.
C99 standard:
When applied to an operand that has array
type, the result is the total number of bytes in the array