Portée des variables



La portée d'une variable désigne les parties du code source où elle est utilisable. Ce peut être par exemple, le projet entier, le fichier dans lequel la variable est déclarée, ou simplement une partie spécifique de ce fichier.

Dans ce cours nous utiliserons le terme de variable globale pour désigner une variable dont la portée est celle du fichier où elle est déclarée.

Inversement, nous dirons qu'une variable est locale si sa portée se restreint à une partie seulement du fichier où elle est déclarée.

En C++, une variable globale est une variable déclarée en dehors de tout bloc d'instructions, c'est à dire un ensemble d'instructions entourées d'accolades. Ce sont donc nécessairement des variables déclarée en dehors du corps du programme principal et en dehors du corps des sous-programmes.

Jusqu'à présent vous avez déclaré les variables avant le programme principal dans un fichier source qui ne contenait pas de sous-programme. Jusqu'ici, toutes les variables que vous avez utilisées dans les exercices de ce cours sont donc des variables globales: elles pouvaient être utilisées dans tout le fichier source.

Pour obtenir une variable locale, il faut la déclarer à l'intérieur d'un bloc d'instruction. Par exemple, à l'intérieur du corps du programme principal ou à l'intérieur du corps d'un sous-programme.

Pour illustrer la différence entre une variable locale et une variable globale, nous commencerons par quelques exemples de programmes.

Ces différents exemples de programmes se trouvent dans le répertoire Exemple-C-Sous-Programme. Vous pouvez donc les ouvrir et les exécuter pour vous aider à mieux comprendre.

Exemple 1

Cet exemple ce trouve dans le dossier:

 Exemple-C-Sous-Programme/Global

La boucle de saisie des données affiche ceci:

Global.jpg, 17kB

et voici un extrait du code de ce programme:

int x;
int choix;

void Affecter_1961_a_X () {
	x = 1961;
}

void Afficher_X () {
	cout << "X = " << x;
}

int main(int argc, char** argv) {

 while (choix!=3) {
   
   ....
   
   switch (choix){

    case 1:  Affecter_1961_a_X (); break;
    case 2:  Afficher_X; break; 
    }
  }
 ...
 }

Dans ce premier exemple, la variable x est déclarée à l'extérieur de tout bloc d'instruction. Il s'agit donc d'une variable globale.

Cela a les conséquences suivantes:

Exemple 2

Cet exemple ce trouve dans le dossier:

 Exemple-C-Sous-Programme/Local0

Le code du programme est identique à celui de Global, mis à part un petit détail : nous déclarons cette fois-ci la variable x à l'intérieur de la procédure Affecter_1961_a_X:

  
int choix;

void Affecter_1961_a_X () {
	int x = 0;
	x = 1961;
}
....
 

On constate alors que le projet n'est pas compilable. Le compilateur C détecte une erreur :

Local0.jpg, 34kB

Cette erreur est localisée dans l'instruction d'affichage de la variable x dans la procédure Afficher_X.

Comment expliquer cette erreur ?

Le problème vient du fait qu'une variable locale n'est accessible qu'à l'intérieur du bloc où elle est déclarée. Autrement dit, la portée d'une variable locale est limitée à ce bloc. Comme x est déclaré dans le corps de la procédure Affecter_1961_a_X, cette variable ne peut pas être utilisée en dehors de cette procédure.

Exemple 3

Cet exemple ce trouve dans le dossier:

 Exemple-C-Sous-Programme/Local1

Il s'agit d'une version légèrement modifiée du programme précédent, dans laquelle la variable x est à la fois déclarée comme une variable globale et comme une variable locale de la procédure Affecter_1961_a_X:

int choix;
int x;

void Affecter_1961_a_X () {
	int x = 0;
	x = 1961;
}

void Afficher_X () {
	cout << "X = " << x;
} 

int main(int argc, char** argv) {
 x = 1935;

 while (choix!=3) { ....    
    

Autre petite différence: la valeur 1935 est affectée à x dans le corps du programme principal.

Cet exemple ne provoque aucun message d'erreur à la compilation.

Vous vous demandez peut-être comment une telle chose est possible. Comment une même variable peut elle être simultanément locale et globale ?

En réalité, il y a deux variables distinctes: la variable x déclarée en global et celle déclarée en local dans la procédure Affecter_1961_a_X.

Bien qu'elles portent le même nom, ces deux variables sont totalement indépendantes.

Mais si le compilateur C rencontre une instruction utilisant x, comment peut-il savoir de quelle variable il s'agit ?

Il s'en sort de la manière suivante:

De manière générale:

La déclaration locale est prioritaire sur la déclaration globale.

Autrement dit, si une variable globale est redéclarée à l'intérieur de certains sous-programmes alors:

A présent, faites l'expérience suivante:

  1. lancez le programme et choisissez Afficher X. Vous constaterez qu'il affiche la valeur 1935 .

  2. choisissez ensuite Affecter la valeur 1961 à X, puis Afficher X. Vous constaterez, que la valeur affichée est toujours 1935. Il semblerait donc que la variable x n'a pas été modifiée.

Comment expliquer ceci ?

Lorsque vous lancez le programme, la première instruction exécutée est l'affectation x = 1935 du programme principal. Comme x n'est pas déclaré à l'intérieur du programme principal, elle agit sur la variable globale x. Lorsque vous exécutez ensuite le choix Afficher X, l'ordinateur exécute la procédure Afficher_X dans laquelle ne figure aucune déclaration locale de la variable x. Cette procédure affiche donc la valeur de la variable globale x qui vaut 1935.

Lorsque vous lancez ensuite l'opération Affecter la valeur 1961 à X, l'ordinateur exécute la procédure Affecter_1961_a_X dans laquelle x est déclarée en local. Cette procédure affecte la valeur 1961 à x. Mais comme x est déclarée dans cette procédure, cette affectation agit sur la variable x déclarée dans cette procédure et non pas sur la variable x déclarée en global.

Enfin, lorsque vous resélectionnez le choix Afficher X, il exécute la procédure Afficher_X dans laquelle ne figure aucune déclaration locale de la variable x. Cette procédure affiche donc la valeur de la variable globale x qui est toujours égale à 1935.

Principes généraux

Définition
Par définition, une variable est locale si elle est déclarée à l'intérieur d'un bloc d'instruction. Elle est globale dans le cas contraire.
Portée
Une variable globale est utilisable par tous les sous-programmes contenus dans le fichier où elle est déclarée.

Une variable locale, au contraire, n'est utilisable qu'à l'intérieur du bloc dans lequel elle est déclarée.
Durée de vie
La durée de vie d'une variable globale est égale à celle du programme. La zone mémoire allouée pour cette variable lui reste allouée tant que le programme s'exécute.

Par contre:

Pour une variable locale la durée de l'allocation mémoire est celle de l'exécution du sous-programme dans laquelle elle est déclarée. Autrement dit, une fois la procédure exécutée l'ordinateur ne peut absolument pas se souvenir de sa dernière valeur !

Durant l'exécution d'un programme, une variable locale peut donc avoir plusieurs vies: elle renait chaque fois que le sous-programme contenant sa déclaration s'exécute et meurt chaque fois qu'il se termine.

Déclarations multiples

Avec les variables locales, il devient possible de déclarer plusieurs fois une variable de même nom.

Si une "même" variable est déclarée en local et en global (voir exemple3):

Nous n'avons pas présenté d'exemple de ce type, mais il est également possible de déclarer plusieurs variables de même nom dans des sous-programmes distincts. Tout se passe alors comme si on avait donné des noms de variables distincts pour ces différentes déclarations. Autrement dit:

Si une variable de même nom est déclarée localement plusieurs fois, chaque déclaration locale engendre une variable totalement indépendante des autres.