web-dev-qa-db-fra.com

Peut-être utiliser une variable constante pour déclarer la taille d'un tableau en C?

Pourquoi le code suivant génère-t-il une erreur?

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

Et aussi, quand j'ai essayé de compiler le code ci-dessus sans le mot-clé "const", j'ai eu la même erreur:

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

pourquoi est-il ainsi? Quelle est l'erreur que je fais ici?

Et aussi une autre question: Quand les constantes sont-elles remplacées par leur valeur réelle dans un code, c'est-à-dire si je déclare une variable, dites: const int x = 5; Je sais qu'aucune mémoire n'est allouée dans RAM pour la variable x, mais la zone de variable constante dans ROM contient la valeur 5 et que x est simplement remplacé par la valeur 5 partout où x apparaît dans le code. Mais quand est-ce que cela se produit? Temps de compilation? Temps de démarrage? Temps de prétraitement?

PS: Je parle d’Embedded C (fonctionnant sur un microcontrôleur, etc.), pas de C fonctionnant sur mon bureau. Donc, le système embarqué doit obligatoirement avoir une ROM (Flash, EEPROM ...). Que se passerait-il alors? 

32
user1901196

C'est simplement une limitation de la langue. Les tailles des tableaux statiquement liés doivent être expressions constantes , et malheureusement en C, cela ressemble à une constante littérale ou à une expression sizeof ou similaire, mais pas une variable const-.

(Comme Simon l'a souligné, depuis C99, il existe aussi runay-bounded arrays, ou "tableaux de longueur variable", dont la taille peut être donnée par la valeur de toute variable. Mais c'est un animal différent.)

Vous serez peut-être intéressé d'apprendre que les règles sont différentes en C++, où static const int est en effet une expression constante, et C++ 11 ajoute même un nouveau mot clé, constexpr, pour permettre l'utilisation encore plus générale d'expressions constantes englobant davantage de choses dont valeur "pourrait raisonnablement être déterminée au moment de la compilation".

34
Kerrek SB

En C, const est un terme impropre pour lecture seule. Les variables const peuvent changer leur valeur, par ex. il est parfaitement correct de déclarer

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

que vous pouvez lire et obtenir une valeur différente à chaque lecture, mais pas écrire. La spécification de langage traite donc les objets qualifiés const not comme des expressions constantes adaptées aux tailles de tableau.

29
Jens

2 alternatives majeures à VLA: enum et macros

Avec enum:

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

Cela fonctionne parce que les membres enum sont des expressions constantes: Le membre enum peut-il avoir la taille d'un tableau dans ANSI-C?

Avec des macros:

#define N 5
int is[N];

L’avantage de enums est que enums a une portée et fait partie de l’étape de compilation, de sorte qu’ils peuvent également générer de meilleurs messages d’erreur.

L'avantage des macros est que vous avez plus de contrôle sur le type des constantes (par exemple #define N 1 vs #define N 1u), alors que enums est fixé à un type défini d'implémentation: Est-ce que sizeof (enum) == sizeof (int), toujours? Mais dans ce cas, peu importe.

Pourquoi éviter VLA

EDIT: Il suffit de lire sur wikipedia que C11 a relégué les tableaux de longueurs variables à une fonctionnalité facultative :( Doh! La première partie du message n’est peut-être pas très utile, mais la seconde partie répond à vos autres questions :)

En complément de l'article de Kerrek SB, C99 (ISO/IEC 9899: 1999) utilise le concept d'un tableau à longueur variable . La norme donne l'exemple suivant:

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

L'opérateur sizeof est étendu comme suit:

L'opérateur sizeof donne la taille (en octets) de son opérande, qui peut être une expression ou le nom entre parenthèses d'un type. La taille est déterminé à partir du type de l'opérande. Le résultat est un entier. Si le type de l'opérande est un type de tableau de longueur variable, l'opérande est évalué; sinon, l'opérande n'est pas évalué et le résultat est une constante entière.

Un autre exemple de Nice peut être trouvé sur wikipedia .

Notez que les déclarations statiques ne peuvent pas être des tableaux de longueur variable.

En ce qui concerne certaines de vos autres questions:

Q: Quand les constantes sont-elles remplacées par leurs valeurs réelles dans un code?

Si la constante est une variable const, elle ne peut jamais être "remplacée" et est toujours accessible en tant que zone de mémoire. En effet, l'opérateur d'adresse & doit toujours travailler avec la variable. Cependant, si l'adresse de la variable n'est jamais utilisée, elle peut être "remplacée" et ne pas avoir de mémoire allouée. De la norme C:

L'implémentation peut placer un objet const qui n'est pas volatil dans un région de stockage en lecture seule. De plus, la mise en œuvre n'est pas nécessaire allouez le stockage pour un tel objet si son adresse n'est jamais utilisée.

Question suivante...

Q: Je sais qu'aucune mémoire n'est allouée dans RAM pour la variable x, mais la zone de variable constante dans ROM contient la valeur 5

Cela dépend de votre système. Si vous avez ROM et que le compilateur sait où se trouve ROM, il se peut qu’il soit placé dans la ROM. S'il n'y a pas de ROM le seul choix que le compilateur (bien l'éditeur de liens) aura est la RAM.

Q: x est simplement remplacé par la valeur 5, partout où x apparaît dans le code. Mais quand cela se produit-il? Temps de compilation? Temps de démarrage? Temps de prétraitement?

Comme indiqué, cela dépend plutôt de la manière dont la constante est utilisée. Si l'adresse de la variable const n'est jamais utilisée et que le compilateur est assez intelligent, alors au moment de la compilation. Sinon, le "remplacement" ne se produit jamais et il s'agit d'une valeur avec un emplacement en mémoire; dans ce cas, le placement de la variable en mémoire se produit au moment de la liaison. Cela se produira jamais pendant le prétraitement.

4
Jimbo

Peut-être que cela vaut la peine de mentionner, ici vous pourriez utiliser

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

Au cas où vous auriez besoin d'un nombre d'éléments

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

Je crois que c'est à la chaîne d'outils, de décider où stocker les constantes, flash ou RAM

1
Iurii