Thursday, March 8, 2018

valid and invalid syntax for representing the size of array during initialisation

Leave a Comment

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment