Does "int size = 10;" yield a constant expression? - c++

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.

Related

Do certain versions of C++ allow dynamic arrays in this way? [duplicate]

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.)

Why there is no compile error for the array definition with non-constant value?

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++.

Difference between const int and int in an array declaration?

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.

g++: array bound is not an integer constant

With the code,
const double rotationStep = 0.001;
const int N = 2*int(M_PI/rotationStep) + 3;
static unsigned int counts[N];
g++ gives the error:
array bound is not an integer constant before »]« token
I am using g++/gcc version 4.6.1
Can anybody tell me why g++ complains about the expression?
As of the ISO C++ standard of 2003, that's not an integral constant-expression. Quoting section 5.19 of the standard:
An integral constant-expression can involve only literals (2.13),
enumerators, const variables or static data members of integral or
enumeration types initialized with constant expressions (8.5),
non-type tem-plate parameters of integral or enumeration types, and
sizeof expressions. Floating literals (2.13.3) can appear only if
they are cast to integral or enumeration types.
You could change this:
const double rotationStep = 0.001;
const int N = 2*int(M_PI/rotationStep) + 3;
to this:
const int inverseRotationStep = 1000;
const int N = 2*int(M_PI)*inverseRotationStep + 3;
(That's assuming M_PI is defined somewhere; it's not specified in the standard, but it's a common extension.)
The 2011 ISO C++ standard loosens this up a bit. 5.19p3 (quoting the N3337 draft) says:
An integral constant expression is a literal constant expression of
integral or unscoped enumeration type.
I think 2*int(M_PI/rotationStep) + 3, and therefore N, qualifies under the new rules, but it's likely your compiler doesn't yet implement them.
The problem is that...
g++ gives: array bound is not an integer constant before »]« token
A const value is not a constant expression (though its quite understandable why this would confuse you).
EDIT: I assumed C when I first read this. The problem here is that this expression is not being evaluated at compile time:
const int N = 2*int(M_PI/rotationStep) + 3;
While this would be
const int N = 10;
As #ildjarn noted in the comments, floating point arithmetic is not guaranteed to be evaluated at compile time. Here is a related SO post I found.
As Ed already pointed out, optimizations of floating point operations, including constant folding, are not guaranteed to happen at compile time. Intel's page on the subject gives a few examples, but mainly it's that the rounding behavior may be different and that floating point operations may throw exceptions. This paper goes a bit more in-depth (section 8.3, "Arithmetic Reduction").
GCC does only support
"floating-point expression contraction such as forming of fused multiply-add operations if the target has native support for them"
as mentioned in the description for the ffp-contract flag in the compiler optimizations manual.

Why can't I initialize a variable-sized array?

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?