38 votes

Pourquoi int x[n] est-il incorrect lorsque n est une valeur constante ?

Je ne comprends pas pourquoi c'est mal de faire ça :

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

même si n est déjà une valeur constante.

Bien que faire cela semble être correct pour le compilateur GNU :

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

Je suis conscient de la fonctionnalité VLA de C99 et je pense qu'elle est liée à ce qui se passe, mais j'ai juste besoin d'une clarification de ce qui se passe en arrière-plan. j'ai juste besoin d'une clarification de ce qui se passe en arrière-plan.

36voto

Keith Thompson Points 85120

Ce qu'il faut retenir, c'est que const et "constante" signifient deux choses bien différentes.

El const signifie en réalité "lecture seule". A constant est un littéral numérique, tel que 42 o 1.5 (ou une énumération ou une constante de caractère). A expression constante est un type particulier d'expression qui peut être évalué au moment de la compilation, tel que 2 + 2 .

Ainsi, une déclaration a été faite :

const int n = 5;

l'expression n fait référence à la valeur de la objet et elle n'est pas traitée comme une expression constante. Un compilateur typique optimisera une référence à n en le remplaçant par le même code qu'il utiliserait pour un littéral 5 mais ce n'est pas obligatoire - et les règles pour savoir si une expression est constant sont déterminées par le langage, et non par l'ingéniosité du compilateur actuel.

Un exemple de la différence entre const (en lecture seule) et constant (évalué au moment de la compilation) est :

const size_t now = time(NULL);

El const signifie que vous n'êtes pas autorisé à modifier la valeur de l'élément now après son initialisation, mais la valeur de time(NULL) ne peuvent clairement pas être calculés avant le moment de l'exécution.

Alors ça :

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

n'est pas plus valable en C qu'elle ne le serait sans l'élément const mot-clé.

La langue pourrait (et IMHO probablement devrait) évaluer n comme une expression constante ; elle n'est simplement pas définie de cette façon. (Le C++ a une telle règle ; voir la norme C++ ou une référence décente pour les détails sanglants).

Si vous voulez une constante nommée avec la valeur 5 La méthode la plus courante consiste à définir une macro :

#define N 5
int x[N];

Une autre approche consiste à définir une constante d'énumération :

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

Les constantes d'énumération sont des expressions constantes, et sont toujours de type int (ce qui signifie que cette méthode ne fonctionnera pas pour les types autres que int ). Et on peut dire que c'est un abus de l'autorité de la enum mécanisme.

À partir de la norme 1999, un tableau peut être défini avec une taille non constante ; c'est un VLA, ou tableau à longueur variable. Ces tableaux ne sont autorisés qu'à l'échelle du bloc et ne peuvent pas avoir d'initialisateur (puisque le compilateur n'est pas en mesure de vérifier que l'initialisateur a le nombre correct d'éléments).

Mais étant donné votre code original :

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

vous pouvez laisser le compilateur déduire la longueur à partir de l'initialisateur :

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

Et vous pouvez alors calculer la longueur à partir de la taille du tableau :

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

21voto

haccks Points 33022

Pourquoi int x[n] est faux lorsque n es un const valeur ?

n n'est pas une constante. const seulement la promesse que n est une variable en lecture seule qui ne doit pas être modifiée pendant l'exécution du programme.
Notez que dans c contrairement à c++ , const Les variables qualifiées ne sont pas constantes. Par conséquent, le tableau déclaré est un tableau de longueur variable.
Vous ne pouvez pas utiliser la liste d'initialisation pour initialiser des tableaux de longueur variable.

C11-§6.7.9/3 :

Le type de l'entité à initialiser doit être un tableau de taille inconnue ou un type d'objet complet qui est pas un type de tableau à longueur variable .

Vous pouvez utiliser #define o enum de faire n une constante

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

7voto

Clifford Points 29933

Si vous initialisez un tableau de manière exhaustive, il est plus facile, plus sûr et plus facile à maintenir de laisser le compilateur déduire la taille du tableau :

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

Ensuite, pour modifier la taille du tableau, il suffit de modifier le nombre d'initialisateurs, plutôt que de modifier la taille. y la liste des initialisateurs à faire correspondre. Particulièrement utile lorsqu'il y a beaucoup d'initialisateurs.

3voto

R Sahu Points 24027

Même si n es un const Vous ne pouvez pas l'utiliser pour définir la taille d'un réseau, sauf si vous souhaitez créer un VLA. En revanche, vous ne pouvez pas utiliser une liste d'initialisation pour initialiser un VLA.

Utilisez une macro pour créer un tableau de taille fixe.

#define ARRAY_SIZE 5

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

2voto

Eric Towers Points 1875

Votre code est-il sémantiquement différent de myfunc() ici :

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;
}

Est n est vraiment si constante que ça ? Combien d'espace pensez-vous que le compilateur devrait allouer pour x[] (puisque c'est le travail du compilateur de le faire) ?

Comme d'autres l'ont souligné, le cv-qualifier const fait no signifie "une valeur qui est constante pendant la compilation et pour tout le temps après". Il signifie "une valeur que le code local n'est pas censé modifier (bien qu'il puisse le faire)".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X