I'm currently studying c array and is confused about what can and can't be used to represent the size of the array during initialisation.
Am I right to assume
#define SIZE 5
and
const int SIZE = 5;
are fundamentally different to one another?
They have their difference and one particular example that confuses me is
#define SIZE 5 int arr[SIZE] = {11, 22, 33, 44, 55};
is valid syntax, but
const int SIZE = 5; int arr[SIZE] = {11, 22, 33, 44, 55};
is not valid syntax. Though interestingly,
const int SIZE = 5; int arr[SIZE];
is valid syntax.
What's the logic behind whether a particular syntax is valid or invalid?
3 Answers
Answers 1
The standard explains it 6.7.9p3
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
In the second case it's a VLA but in the first case it is not. After preprocessing it is same as int arr[5] = {..}
.
In the VLA case, the compiler doesn't know the size of a VLA when it's defined, so it can't check validity of an initializer. That's why this initialization is not allowed.
By the way, using const
doesn't mean that it is a compile time constant - it just means it can't be changed.
Also from 6.7.6.2p4 there is a clear distinction about when it is VLA and when it is not:-
...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.
Answers 2
Am I right to assume
#define SIZE 5
and
const int SIZE = 5;are fundamentally different to one another?
Yes, you are right.
#define
is simply a[ textual replacement. Basically, the C preprocessor is going a "find and replace" for you during the compilation process (processing stage). Whereas, const
qualified object means "the thing stored at this location can't changed" - roughly equivalent to saying it's "read-only".
#define SIZE 5
int arr[SIZE] = {11, 22, 33, 44, 55};is valid syntax.
This is exactly equivalent to writing:
int arr[5] = {11, 22, 33, 44, 55};
yourself. The compiler simply does the replacement job for you when you use define
.
const int SIZE = 5;
int arr[SIZE] = {11, 22, 33, 44, 55};
is not valid syntax.
It's invalid but the reason could be more than one. If arr
has static storage duration (i.e., the object arr
is alive throughout the program execution) then it's invalid. Because C requires that the size of an array object with static storage duration to be a constant expression:
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.
So, the following program is not valid:
const int SIZE = 5; int arr[SIZE] = {11, 22, 33, 44, 55}; int main(void) { }
because SIZE
doesn't qualify as a "constant expression" in C. Note that this is totally valid in C++ where SIZE
qualifies as a constant expression (the two languages differ here).
Another reason is C standard doesn't allow initializing variable-length arrays. If you have the definition inside a function such as:
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
So if you don't have the initializer then it becomes valid:
int main(void) { const int SIZE = 5; int arr[SIZE]; /* This is OK */ }
Similarly, you can do without the const
as well:
int main(void) { int SIZE = 5; int arr[SIZE]; /* Thi is OK too. */ }
In both of the above snippets, arr
is simply a variable-length array.
Though interestingly,
const int SIZE = 5; int arr[SIZE];
is valid syntax.
It's valid only if it's inside a function (as above) - it's a VLA. But if you make it have static storage duration such as:
const int SIZE = 5; int arr[SIZE]; /* arr has static storage duration just as all objects defined at file scope */ int main(void) { }
it's invalid because as noted above, SIZE
is not a "constant expression" in C.
Similarly,
int main(void) { const int SIZE = 5; static int arr[SIZE]; /* arr has static storage duration */ }
is invalid for the same reason, despite arr
being inside a function, because arr
has static storage duration.
However, if you have:
enum {SIZE = 5}; int arr[SIZE] = {11, 22, 33, 44, 55}; int arr2[SIZE]; /* Valid without initializer too. */ int main() { }
it's valid. Why? Because enum constants qualify as "constant expressions" in C.
Answers 3
#define SIZE 5
define SIZE
an integer constant expression. While const int SIZE = 5;
defines SIZE
as a variable expression that's value shall not be modified. const
qualifier doesn't make it an integer constant expression (in c++ it does so).
Standard says
n1570-§6.7.6.2 (p4):
[...] 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. [...]
When you do
#define SIZE 5 int arr[SIZE] = {11, 22, 33, 44, 55};
it declare arr
as an array which is not a variable length array (VLA). While
const int SIZE = 5; int arr[SIZE];
declares arr
as a variable length array because SIZE
is not a integer constant expression, but a variable expression. But same declaration fails with initializer list and that's because there is a restriction on VLA's is they can't be initialized using list intializers.
§6.7.9 (p2 and p3):
No initializer shall attempt to provide a value for an object not contained within the entity being initialized.
The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.
0 comments:
Post a Comment