Portée des variables

Une variable peut être de portée locale ou globale. Elle est globale si elle est déclarée en dehors de tout sous-programme. Au contraire, une variable locale est déclarée à l'intérieur d'un sous-programme.

Mais pour l'instant, nous n'avons pas défini ce qu'est un sous-programme de manière générale. Par contre, vous savez ce qu'est une procédure évènementielle. Or, les procédures évènementielles représentent une catégorie particulière de sous-programme.

Nous allons donc, pour l'instant, baser nos explications concernant la portée des variables en utilisant uniquement les procédures évènementielles. Gardez toutefois à l'esprit que ces explications seront valables pour n'importe quel type de sous-programme.

Les variables locales et globales ne se comportent pas de la même manière, notamment en ce qui concerne leur durée de vie.

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/Pascal. Vous pouvez donc les ouvrir et les exécuter pour vous aider à mieux comprendre ou pour vous convaincre.

Exemple 1 ( Fichier : Global/ProjetGlobal.lpi)

Voici le formulaire du programme:

LZ-Global.jpg, 13kB

et voici un extrait du code de ce programme:

var
  Form1: TForm1; 
  x : integer;

implementation


procedure TForm1.BoutonAffecterClick(Sender: TObject);
begin
  x := 1961;
end;

procedure TForm1.BoutonAfficherClick(Sender: TObject);
begin
  AfficherEntier (x, ZoneTexteX);
end;
 

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

Cela a les conséquences suivantes:

Exemple 2 ( Fichier : Local0/ProjetLocal0.lpi)

Déclarons cette fois-ci la variable x à l'intérieur de la procédure BoutonAffecterClick. On obtient le résultat suivant:

LZ-Local0.jpg, 79kB

Lazarus affiche un message d'erreur Identifier not found "X". Cette erreur est localisée dans l'instruction AfficherEntier(x, ZoneTexteX) de la procédure BoutonAfficherClick.

Lazarus prétend ne pas connaître l'identificateur x dont on parle dans cette instruction.

Or nous avons bien déclaré x !

Comment expliquer cette erreur ?

Le problème vient du fait qu'une variable locale n'est accessible qu'à l'intérieur du sous-programme où elle est déclarée. Autrement dit, la portée d'une variable locale est limitée à ce sous-programme.

Dans notre exemple, x n'est donc définie qu'à l'intérieur de la procédure BoutonAffecterClick et nul part ailleurs.

Exemple 3 ( Fichier : Local1/ProjetLocal1.lpi)

Voici à présent une version légèrement modifiée du programme précédent, dans laquelle la variable x est déclarée au début du programme ainsi qu'à l'intérieur de la procédure BoutonAffecterClick:

var
  Form1: TForm1;
  x : integer;

implementation

procedure TForm1.BoutonAffecterClick(Sender: TObject);
var x : integer;
begin
  x := 1961;
end;

procedure TForm1.BoutonAfficherClick(Sender: TObject);
begin
  AfficherEntier (x, ZoneTexteX);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  x := 1935;
  AfficherEntier (x, ZoneTexteX);
end;  
 

Cet exemple ne provoque aucun message d'erreur.

Vous vous demandez peut-être comment une telle chose est possible, car a priori une variable ne peut pas être déclarée deux fois. On devrait avoir un message d'erreur. Or il n'en est rien !

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

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

Mais si Lazarus 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. Il affiche la valeur 1935 pour x:

  2. cliquer sur le bouton Affecter la valeur 1961 à X, puis sur Afficher X. Résultat:
    la variable x n'a pas été modifiée !

Comment expliquer ceci ?

Lorsque vous lancez le programme, Lazarus exécute tout d'abord la procédure FormCreate. Celle-ci affecte la valeur 1935 à la variable x déclarée en globale, puis affiche la valeur de cette même variable.

Lorsque vous cliquez sur le bouton Affecter la valeur 1961 à X, il exécute la procédure BoutonAffecterClick dans laquelle x est déclarée en local. Cette même 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 cliquez sur le bouton Afficher X, il exécute la procédure BoutonAfficherClick 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.

Exemple 4 ( Fichier : Local2/ProjetLocal2.lpi)

Cette fois-ci, nous déclarons x en local dans toutes les procédures, mais pas en global:

var
  Form1: TForm1;

implementation

procedure TForm1.BoutonAffecterClick(Sender: TObject);
var x : integer;
begin
  x := 1961;
end;

procedure TForm1.BoutonAfficherClick(Sender: TObject);
var x : integer;
begin
  AfficherEntier (x, ZoneTexteX);
end;

procedure TForm1.FormCreate(Sender: TObject);
var x : integer;
begin
  x := 1935;
  AfficherEntier (x, ZoneTexteX);
end;  

Nous avons en réalité ici trois variables locales x indépendantes: celle de la procédure BoutonAffecterClick, celle de la procédure BoutonAfficherClick et celle de la procédure FormCreate.

Même expérience qu'avant:

  1. lancez le programme. Il affiche la valeur 1935 pour x:
  2. cliquer sur le bouton Affecter la valeur 1961 à X, puis sur Afficher X. La valeur affiché est (très très probablement) différente de 1961.

Explications:

Lorsque vous lancez le programme, Lazarus exécute FormCreate. Ce sous-programme affecte la valeur 1935 à la variable locale x, puis affiche la valeur de cette même variable.

Lorsque vous cliquez sur le bouton Affecter la valeur 1961 à X, il exécute le sous-programme BoutonAffecterClick qui affecte la valeur 1961 à la variable locale x de cette procédure. .

Enfin, lorsque vous cliquez sur le bouton Afficher X, il exécute le sous-programme BoutonAfficherClick qui affiche la valeur de la variable locale x de cette procédure. Comme aucune valeur n'est affectée à x dans cette procédure, cette variable a donc une valeur indéfinie.

Synthèse

Voilà en résumé ce qu'il faut retenir sur les variables locales et globales:

Définition
Par définition, une variable est locale si elle est déclarée à l'intérieur d'un sous-programme. 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 sous-programme 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.
La durée de vie d'une variable locale est celle d'une exécution du sous-programme dans lequell elle est déclarée. Elle peut donc avoir plusieurs vies: elle renait chaque fois que le sous-programme s'exécute et meurt chaque fois qu'il se termine.
Déclarations locales multiples
Si une "même" variable est déclarée dans plusieurs sous-programmes, tout se passe comme si on avait donné des noms de variables distincts pour ces différentes déclarations. Autrement dit, chaque déclaration engendre une variable totalement indépendante des autres.
Déclaration simultanée en local et en global
Si une "même" variable est déclarée en local et en global: