Why is int x[n] wrong where n is a const value?

ⅰ亾dé卋堺 提交于 2019-11-27 14:20:26

问题


I cannot understand why doing this is wrong:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

even though n is already a const value.

While doing this seems to be right for the GNU compiler:

const int n = 5;
int x[n]; /*without initialization*/

I'm aware of VLA feature of C99 and I think it's related to what's going on but I just need some clarification of what's happening in the background.


回答1:


The key thing to remember is that const and "constant" mean two quite different things.

The const keyword really means "read-only". A constant is a numeric literal, such as 42 or 1.5 (or an enumeration or character constant). A constant expression is a particular kind of expression that can be evaluated at compile time, such as 2 + 2.

So given a declaration:

const int n = 5;

the expression n refers to the value of the object, and it's not treated as a constant expression. A typical compiler will optimize a reference to n, replacing it by the same code it would use for a literal 5, but that's not required -- and the rules for whether an expression is constant are determined by the language, not by the cleverness of the current compiler.

An example of the difference between const (read-only) and constant (evaluated at compile time) is:

const size_t now = time(NULL);

The const keyword means you're not allowed to modify the value of now after its initialization, but the value of time(NULL) clearly cannot be computed until run time.

So this:

const int n = 5;
int x[n];

is no more valid in C than it would be without the const keyword.

The language could (and IMHO probably should) evaluate n as a constant expression; it just isn't defined that way. (C++ does have such a rule; see the C++ standard or a decent reference for the gory details.)

If you want a named constant with the value 5, the most common way is to define a macro:

#define N 5
int x[N];

Another approach is to define an enumeration constant:

enum { n = 5 };
int x[n];

Enumeration constants are constant expressions, and are always of type int (which means this method won't work for types other than int). And it's arguably an abuse of the enum mechanism.

Starting with the 1999 standard, an array can be defined with a non-constant size; this is a VLA, or variable-length array. Such arrays are permitted only at block scope, and may not have initializers (since the compiler is unable to check that the initializer has the correct number of elements).

But given your original code:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

you can let the compiler infer the length from the initializer:

int x[] = { 1,1,3,4,5 };

And you can then compute the length from the array's size:

const int x_len = sizeof x / sizeof x[0];



回答2:


Why int x[n] is wrong where n is a const value?

n is not a constant. const only promise that n is a 'read-only' variable that shouldn't be modified during the program execution.
Note that in c, unlike c++, const qualified variables are not constant. Therefore, the array declared is a variable length array.
You can't use initializer list to initialize variable length arrays.

C11-§6.7.9/3:

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.

You can use #define or enum to make n a constant

#define n 5
int x[n] = { 1,1,3,4,5 };   



回答3:


If you are exhaustively initialising an array, then it is easier, safer and more maintainable to let the compiler infer the array size:

int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ; 

Then to change the array size you only have to change the number of initialisers, rather than change the size and the initialiser list to match. Especially useful when there are many initialisers.




回答4:


Even though n is a const, you cannot use it to define the size of an array unless you wish to create a VLA. However, you cannot use an initializer list to initialize a VLA.

Use a macro to create a fixed size array.

#define ARRAY_SIZE 5

int x[ARRAY_SIZE] = { 1,1,3,4,5 };



回答5:


Is your code semantically different from myfunc() here:

void myfunc(const int n) { 
    int x[n] = { 1,1,3,4,5 };
    printf("%d\n", x[n-1]);
    *( (int *) &n) = 17;    //  Somewhat less "constant" than hoped...
    return ;
}

int main(){
    myfunc(4);
    myfunc(5);
    myfunc(6);  //  Haven't actually tested this.  Boom?  Maybe just printf(noise)?
    return 0;
}

Is n really all that constant? How much space do you think the compiler should allocated for x[] (since it is the compiler's job to do so)?

As others have pointed out, the cv-qualifier const does not mean "a value that is constant during compilation and for all times after". It means "a value that the local code is not supposed to change (although it can)".



来源:https://stackoverflow.com/questions/35162043/why-is-int-xn-wrong-where-n-is-a-const-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!