Ardu? No!Initiation ≫ Portée des variables

Portée des variables

Reprenons un des programmes de l'étape précédente, par exemple:

int cacheCache;

void setup(void) {
  Serial.begin(115200);
}

void loop() {
  cacheCache = cacheCache + 1;
  Serial.println(cacheCache);
  delay(1000);
}

Ici, nous allons nous intéresser à la place de la ligne int cacheCache;

Notion de portée

Portons la ligne de déclaration de la variable tout à la fin. En compilant (en essayant de transvaser), on déclenche une erreur 'cacheCache' was not declared in this scope (= 'cacheCache n'a pas été déclarée dans cette portée") sur la première ligne ou cacheCache est utilisée. Cela vient du fait que la variable étant définie après, elle n'est pas encore connue quand on en a besoin. On va alors parler de portée d'une variable. C'est les lieux ou elle la variable est définie. Cela débute à sa déclaration et cela s'arrête à la fin du bloc dans laquelle elle est définie. Je n'ai pas encore parlé de blocs, on en verra plus dans le détail ultérieurement, mais nous allons nous débrouiller. Retenez qu'un bloc est un ensemble d'instructions souvent délimité par un couple d'accolades.

Je vais dessiner par une ligne rouge la portée de cacheCache. Dans le tout premier programme sa portée commence à sa déclaration. setup est un bloc, mais notre variable est définie avant à l'extérieur. Elle sera donc définie aussi dans tout le setup(). C'est pareil pour loop(). Enfin sa portée s'arrête à la fin du programme. Cela donne:

Image: Portée globale sur tout

On parlera de variable globale pour indiquer qu'elle est déclarée à l'extérieur de toute fonction.

Si on met la déclaration de cacheCache tout à la fin, cela donne:

Image: Portée globale en dernière ligne

Notre variable n'est effectivement pas utilisable là où l'on en a besoin. Elle est toujours globale, mais cela n'a pas d'intérêt.

Continuons nos essais, et mettons une définition en tout début et une définition tout à la fin. Vous devez alors obtenir une erreur redefinition of 'int cacheCache'. Il y a une redéfinition et la compilation ne fonctionne pas. Il y a donc deux variable de même nom qui sont toutes les deux globales. Une est de trop.

Juste pour voir, mettons une première déclaration en première ligne, mais ajoutons-en une de plus (double définition) dans setup. Comme on la définit deux fois, on pourrait s'attendre, comme précédemment, à une erreur de compilation. Essayez, il n'y en a pas! Pour le C, et malgré que les noms soient identiques, il y a deux variables différentes, l'une globale sur l'ensemble du programme, et l'autre à l'intérieure de setup. Il n'y a pas redéfinition et donc pas d'erreur. Cela donne:

Image: Portée locale à loop

A un moment donné, nous avons les deux portées; mais comme nous avons le même nom, il n'y en a qu'une accessible. C'est celle qui est la dernière définie. La variable globale existe toujours mais n'est plus accessible.

Comme nous en avons besoin que dans loop() essayons de la mettre à l'intérieur du bloc loop(). Cela compile sans problème, et la portée commence toujours à sa définition et finit à la fin de loop car c'est le bloc dans laquelle elle est définie. Cela donne:

Image: Portée locale à loop

Chouette, elle est bien définie quand on en a besoin. Elle n'est plus globale car elle est définie dans un bloc. On parlera de portée locale. Mais il y a un problème quand le code s'exécute! On n'a plus que des "1". Cela vient du fait que quand on la déclare, elle est initialisée à 0, et à chaque fois que l'on répète loop(), elle se remet à zéro à cause de l'initialisation. On peut quand même s'en sortir en la définissant par le mot réservé static:

static int cacheCache;

Elle reste locale par sa portée, mais se comporte comme une variable globale. Elle sera donc initialisée une seule fois.

Avec loop() ce n'est pas le cas, mais si c'était une autre fonction, on pourrait sortir de la fonction et ré-rentrer dedans, elle conserverait sa valeur.
Cela a un intérêt si on a plusieurs fonctions qui ont toutes besoin d'une variable globale de même nom. En les déclarant static à l'intérieur des fonctions, elles sont locales, et il n'y a pas de conflits.

L'emploi de variable déclarée static reste toutefois rare.