• Aucun résultat trouvé

Chapitre 3. Types avancés et classes de stockage

3.6. Les classes de stockage

Les variables C/C++ peuvent être créées de différentes manières. Il est courant, selon la manière dont elles sont créées et la manière dont elles pourront être utilisées, de les classer en différentes catégories de variables.

La classification la plus simple que l’on puisse faire des variables est la classification locale - globale.

Les variables globalessont déclarées en dehors de tout bloc d’instructions, dans la zone de décla-ration globale du programme. Les variables localesen revanche sont créées à l’intérieur d’un bloc d’instructions. Les variables locales et globales ont des durées de vie, des portées et des emplace-ments en mémoire différents.

La portée d’une variable est la zone du programme dans laquelle elle est accessible. La portée des variables globales est tout le programme, alors que la portée des variables locales est le bloc d’instructions dans lequel elles ont été créées.

Ladurée de vied’une variable est le temps pendant lequel elle existe. Les variables globales sont créées au début du programme et détruites à la fin, leur durée de vie est donc celle du programme. En général, les variables locales ont une durée de vie qui va du moment où elles sont déclarées jusqu’à la sortie du bloc d’instructions dans lequel elles ont été déclarées. Cependant, il est possible de faire en sorte que les variables locales survivent à la sortie de ce bloc d’instructions, et soient à nouveau utilisables dès que l’on y entre à nouveau.

Note : La portée d’une variable peut commencer avant sa durée de vie si cette variable est déclarée après le début du bloc d’instructions dans lequel elle est déclarée. La durée de vie n’est donc pas égale à la portée d’une variable.

Laclasse de stockaged’une variable permet de spécifier sadurée de vieet saplace en mémoire(sa portée est toujours le bloc dans lequel la variable est déclarée). Le C/C++ dispose d’un éventail de classes de stockage assez large et permet de spécifier le type de variable que l’on désire utiliser :

Tableau 3-1. Classes de stockages

Classe Signification

auto Classe de stockage par défaut. Les variables ont pour portée le bloc d’instructions dans lequel elles ont été crées. Elles ne sont accessibles que dans ce bloc. Leur durée de vie est restreinte à ce bloc.

Chapitre 3. Types avancés et classes de stockage

Classe Signification

static Classe de stockage permettant de créer des variables dont la portée est le bloc d’instructions en cours, mais qui, contrairement aux variablesauto, ne sont pas détruites lors de la sortie de ce bloc. À chaque fois que l’on rentre dans ce bloc d’instructions, les variables statiques existeront et auront pour valeurs celles qu’elles avaient avant que l’on quitte ce bloc. Leur durée de vie est donc celle du programme, et elles conservent leurs valeurs. Un fichier peut être considéré comme un bloc. Ainsi, une variable statique d’un fichier ne peut pas être accédée à partir d’un autre fichier.

Cela est utile pour isoler des variables globales d’un fichier vis à vis des autres modules (voir le Chapitre 6 pour plus de détails).

extern Classe de stockage utilisée dans les déclarations pour signaler que la variable ainsi déclarée peut être définie dans un autre fichier que le fichier courant. Elle est utilisée dans le cadre de la compilation séparée (voir le Chapitre 6 pour plus de détails).

register Classe de stockage permettant de créer une variable dont l’emplacement se trouve dans un registre du microprocesseur. Il faut bien connaître le langage machine pour correctement utiliser cette classe de variable. En pratique, cette classe est très peu utilisée, et on péfère de nos jours laisser le compilateur gérer lui-même l’usage des registres du processeur.

volatile Cette classe de stockage sert lors de la programmation système. Elle indique qu’une variable peut être modifiée en arrière-plan par un autre programme (par exemple par une interruption, par un thread, par un autre processus, par le système d’exploitation ou par un autre processeur dans une machine parallèle). Cela nécessite donc de recharger cette variable à chaque fois qu’on y fait référence dans un registre du processeur, et cemême si elle se trouve déjà dans un de ces registres(ce qui peut arriver si on a demandé au compilateur d’optimiser le programme).

Note :Le C++ dispose d’un mécanisme plus souple d’isolation des entités propres à un fichier que ce que permet le mot cléstatic, via le mécanisme des espaces de nommages. De plus, le mot clefstatica une autre signification en C++ dans un autre contexte d’utilisation. L’emploi de ce mot clé pour rendre local à un fichier une variable globale est donc déconseillée en C++, et l’on utilisera de préférence les mécanismes présentés dans le Chapitre 10.

Il existe également des modificateurs pouvant s’appliquer à une variable pour préciser sa constance : Tableau 3-2. Qualificatifs de constance

Qualifi-catif

Signification

Chapitre 3. Types avancés et classes de stockage

Qualifi-catif

Signification

const Ce mot clé est utilisé pour rendre le contenu d’une variable non modifiable. En quelque sorte, la variable devient ainsi une variable en lecture seule. Attention, une telle variable n’est pas forcément une constante : elle peut être modifiée soit par l’intermédiaire d’un autre identificateur, soit par une entité extérieure au programme (comme pour les variablesvolatile). Quand ce mot clé est appliqué à une structure, aucun des champs de la structure n’est accessible en écriture. Bien qu’il puisse paraître étrange de vouloir rendre « constante » une « variable », ce mot clé a une utilité. En particulier, il permet de faire du code plus sûr et dans certains circonstance permet au compilateur d’effectuer des optimisations.

mutable Ce mot clé n’est disponible qu’en C++. Il ne peut être appliqué qu’aux membres des structures. Son rôle est de permettre de passer outre la constance éventuelle d’une structure pour un membre particulier. Ainsi, un champ de structure déclarémutable peut être modifié même si sa structure contenante est déclaréeconst.

Pour déclarer une classe de stockage particulière, il suffit de faire précéder ou suivre le type de la variable par l’un des mots clésauto,static,register, etc. On n’a le droit de n’utiliser que les classes de stockage non contradictoires. Par exemple,registeretexternsont incompatibles, de même queregisteretvolatile, etconstetmutable. Par contre,staticetconst, de même queconstetvolatile, peuvent être utilisées simultanément.

Exemple 3-17. Déclaration d’une variable locale statique

int appels(void) {

static int n = 0;

return n = n+1;

}

Cette fonction mémorise le nombre d’appels qui lui ont été faits dans la variable n et renvoie ce nombre. En revanche, la fonction suivante :

int appels(void) {

int n = 0;

return n =n + 1;

}

renverra toujours1. En effet, la variablenest créée, initialisée, incrémentée et détruite à chaque appel.

Elle ne survit pas à la fin de l’instructionreturn. Exemple 3-18. Déclaration d’une variable constante

const int i=3;

iprend la valeur3et ne peut plus être modifiée.

Les variables globales qui sont définies sans le mot cléconstsont traitées par le compilateur comme des variables de classe de stockageexternpar défaut. Ces variables sont donc accessibles à partir de tous les fichiers du programme. En revanche, cette règle n’est pas valide pour les variables définies avec le mot cléconst. Ces variables sont automatiquement déclaréesstaticpar le compilateur, ce

Chapitre 3. Types avancés et classes de stockage

qui signifie qu’elles ne sont accessibles que dans le fichier dans lequel elles ont été déclarées. Pour les rendre accessibles aux autres fichiers, il faut impérativement les déclarer avec le mot cléextern avant de les définir.

Exemple 3-19. Déclaration de constante externes

int i = 12; /* i est accessible de tous les fichiers. */

const int j = 11; /* Synonyme de "static const int j = 11;". */

extern const int k; /* Déclare d’abord la variable k... */

const int k = 12; /* puis donne la définition. */

Notez que toutes les variables définies avec le mot clé constdoivent être initialisées lors de leur définition. En effet, on ne peut pas modifier la valeur des variablesconst, elles doivent donc avoir une valeur initiale. Enfin, les variables statiques non initialisées prennent la valeur nulle.

Les mots clésconstetvolatiledemandent au compilateur de réaliser des vérifications addition-nelles lors de l’emploi des variables qui ont ces classes de stockage. En effet, le C/C++ assure qu’il est interdit de modifier (du moins sans magouiller) une variable de classe de stockageconst, et il assure également que toutes les références à une variable de classe de stockagevolatilese feront sans optimisations dangereuses. Ces vérifications sont basées sur le type des variables manipulées.

Dans le cas des types de base, ces vérifications sont simples et de compréhension immédiate. Ainsi, les lignes de code suivantes :

const int i=3;

int j=2;

i=j; /* Illégal : i est de type const int. */

génèrent une erreur parce qu’on ne peut pas affecter une valeur de type int à une variable de type const int.

En revanche, pour les types complexes (pointeurs et références en particulier), les mécanismes de vérifications sont plus fins. Nous verrons quels sont les problèmes soulevés par l’emploi des mots clésconstetvolatileavec les pointeurs et les références dans le chapitre traitant des pointeurs.

Enfin, en C++ uniquement, le mot clé mutable permet de rendre un champ de structure const accessible en écriture :

Exemple 3-20. Utilisation du mot clé mutable

struct A {

int i; // Non modifiable si A est const.

mutable int j; // Toujours modifiable.

};

const A a={1, 1}; // i et j valent 1.

int main(void) {

a.i=2; // ERREUR ! a est de type const A ! a.j=2; // Correct : j est mutable.

return 0;

}