Can a const variable be used to declare the size of an array in C?

CArraysConstants

C Problem Overview


Why does the following code throw an error?

const int a = 5;
int b[a]={1,2,3,4,5};

And also when I tried to compile the above code without "const" keyword, I got the same error:

int a = 5; 
int b[a]={1,2,3,4,5};

why is it so? What is the mistake that I am doing here?

And also another question: When are constants replaced with their actual values in a code, i.e if I declare a variable say: const int x= 5; I know that no memory is allocated in RAM for the variable x, but constant variable area in ROM holds the value 5 and that x is simply replaced by the value 5 everywhere x appears in the code. But when does this happen? Compilation time? Boot up time? Preprocessing time?

PS: I am talking about Embedded C (running on a Microcontroller etc), not C running on my desktop. So the embedded system is bound to have a ROM (Flash, EEPROM...). What would happen then?

C Solutions


Solution 1 - C

It's simply a limitation of the language. The sizes of statically-bounded arrays need to be constant expressions, and unfortunately in C that's only something like a literal constant or a sizeof expression or such like, but not a const-typed variable.

(As Simon pointed out, since C99 there are also runtime-bounded arrays, or "variable-length arrays", whose size can be given by the value of any variable. But that's a different animal.)

You may be interested to hear that the rules are different in C++, where a static const int is indeed a constant expression, and C++11 even adds a new keyword, constexpr, to allow even more general use of constant expressions which encompass more things whose value "could reasonably be determined at compile time".

Solution 2 - C

In C, const is a misnomer for read-only. const variables can change their value, e.g. it is perfectly okay to declare

const volatile int timer_tick_register; /* A CPU register. */

which you can read and get a different value with each read, but not write to. The language specification thus treats const qualified objects not as constant expressions suitable for array sizes.

Solution 3 - C

2 major alternatives to VLA: enum and macros

With an anonymous enum:

enum { N = 5 };
int is[N];

as in:

#include <stdio.h>

enum { N = 5 };
char is[N];

int main(void) {
    printf("%ju\n", sizeof(is));
}

This works because enum members are constant expressions: https://stackoverflow.com/questions/13770314/can-enum-member-be-the-size-of-an-array-in-ansi-c

With macros:

#define N 5
int is[N];

The advantage of enums is that enums have scope, and are part of the compilation step, so they may lead to better error messages as well.

The advantage of macros is that you have more control over the type of the constants (e.g. #define N 1 vs #define N 1u), while enums are fixed to some implementation defined type: https://stackoverflow.com/questions/1113855/is-the-sizeofenum-sizeofint-always But it doesn't matter much in this case.

Tested on Ubuntu 21.04, GCC 10.3.0, gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c.

Why avoid VLA

Solution 4 - C

EDIT: Just read on wikipedia that C11 has relegated variable length arrays to an optional feature :( Doh! The first half of the post may not be that useful but the second half answers some of your other questions :)

As an extra to Kerrek SB's post, C99 (ISO/IEC 9899:1999) does have the concept of a variable length array. The standard gives the following example:

#include <stddef.h>
size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}

The sizeof operator is extended as follows:

> The sizeof operator yields the size (in bytes) of its operand, which > may be an expression or the parenthesized name of a type. The size is > determined from the type of the operand. The result is an integer. If > the type of the operand is a variable length array type, the operand > is evaluated; otherwise, the operand is not evaluated and the result > is an integer constant.

Another nice example can be found on wikipedia.

Note that statically declared cannot be variable length arrays.

As for some of your other questions:

> Q: When are constants replaced with their actual values in a code?

If the constant is a const variable then it may never be "replaced" and could always be accessed as an area of memory. This is because the address-of operator & still has to work with the variable. However, if the variable address is never used then it can be "replaced" and have no memory allocated. From the C standard:

> The implementation may place a const object that is not volatile in a > read-only region of storage. Moreover, the implementation need not > allocate storage for such an object if its address is never used.

Next question...

> Q: I know that no memory is allocated in RAM for the variable x, but constant variable area in ROM holds the value 5

This depends on your system. If you have ROM and the compiler knows where ROM is located then it may well be placed in ROM. If there is no ROM the only choice the compiler (well linker really) will have is RAM.

> Q: x is simply replaced by the value 5 everywhere x appears in the code. But when does this happen? Compilation time? Boot up time? Preprocessing time?

As noted, this rather depends on how the constant is used. If the address of the const variable is never used and the compiler is clever enough, then at complilation time. Otherwise the "replacement" never occurs and it is a value with a location in memory; in this case the placement of the variable in memory happens at link time. It will never occur during preprocessing.

Solution 5 - C

Maybe it is worth to mention, here you could use

int b[] = {1, 4, 5};

In case you will need number of elements

 size_t sz = sizeof(b)/sizeof(b[0]);

I believe it is up to tool chain, to decide where to store constants, flash or RAM

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1901196View Question on Stackoverflow
Solution 1 - CKerrek SBView Answer on Stackoverflow
Solution 2 - CJensView Answer on Stackoverflow
Solution 3 - CCiro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 4 - CJimboView Answer on Stackoverflow
Solution 5 - CIurii VasylenkoView Answer on Stackoverflow