Can a const variable be used to declare the size o

2019-01-02 21:09发布

问题:

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?

回答1:

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



回答2:

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.



回答3:

2 major alternatives to VLA: enum and macros

With enum:

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

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 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: Is the sizeof(enum) == sizeof(int), always? But it doesn't matter much in this case.

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)


回答4:

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.



回答5:

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



标签: