Can a const variable be used to declare the size of an array in 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".
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.
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: Can enum member be the size of an array in ANSI-C?
With macros:
#define N 5
int is[N];
The advantage of enum
s is that enum
s 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 enum
s are fixed to some implementation defined type: Is the sizeof(enum) == sizeof(int), 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
- are not in C89, and only optional in C11
- may incur an overhead: Is there any overhead for using variable-length arrays? (likely little)
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.