Trois façons de déclarer des constantes

. Par : Jean-Luc. URL : https://www.locoduino.org/spip.php?article102

La notion de constante et ce qui différencie une constante d’une variable a déjà été abordé dans « Types, constantes et variables ». L’usage d’une constante au lieu d’une variable quand il y a lieu de le faire est primordial. Tout d’abord, une constante n’occupe pas de place dans la mémoire de l’Arduino. Il s’agit ici de la mémoire de données qui, sur les Arduino à base d’AVR est très petite, 2048 octets [1]. Le compilateur C qui est caché sous l’IDE Arduino peut utiliser des optimisations qui ne sont pas possibles pour des variables. Enfin, une constante ne peut être modifiée inopinément par une erreur du programme, ce qui réduit la possibilité d’un comportement erroné.

Déclaration avec le mot-clé const

Nous y avons vu la déclaration d’une constante sous cette forme :

const byte pinDEL = 10;

const indique qu’il s’agit d’une constante, byte est le type de la constante, pinDEL est le nom de la constante et 10 sa valeur.

Il s’agit de la forme la plus robuste. En effet, le compilateur connaît le type de la constante, vous êtes donc assuré de la manière dont les calculs sont faits en fonction du type des opérandes. Pour plus de précision, voir dans l’article « Calculer avec l’Arduino (1) », la partie sur les nombres flottants. Cette forme est donc à utiliser en priorité.

Déclaration avec un #define

Ce type de déclaration ne fait pas réellement partie du langage de l’Arduino. En effet, elle est prise en charge par le préprocesseur. Le préprocesseur est une sorte de machine a copier-coller qui fait son travail avant le compilateur. La déclaration suivante :

#define pinDEL 10

rend pinDEL équivalent à 10. Le préprocesseur examine le programme et remplace tous les pinDEL par 10. Le compilateur fait ensuite son travail.

Ce type de déclaration est ce que l’on appelle une macro. Comme cette déclaration n’est pas du C, il n’y a pas de point-virgule à la fin. Une macro se termine tout simplement à la fin de la ligne. Nous verrons dans un prochain article les pièges qui peuvent se cacher dans les macros et comment s’en prémunir.

Déclaration avec le mot-clé enum

C’est une façon très pratique de déclarer plusieurs constantes de valeurs différentes mais dont la valeur n’est pas importante. Il s’agit juste de disposer de noms au lieu de valeurs numériques. On s’en sert essentiellement pour déclarer les états d’un système comme par exemple l’état d’un feu ou l’état interne d’un protocole de communication. On utilise généralement ces constantes pour les cas d’un switch ... case, voir à ce propos « Instructions conditionnelles : le switch ... case ». L’avantage par rapport à const ou #define est que l’on a l’assurance que les valeurs des constantes sont différentes les unes des autres. La déclaration est également plus compacte.

Voici donc la déclaration d’un enum anonyme :

enum { VERT, JAUNE, ROUGE };

Cette déclaration a pour effet de définir 3 constantes, VERT, JAUNE et ROUGE. Les valeurs n’ont pas d’importance. Ces 3 constantes permettent juste d’écrire de manière plus lisible qu’avec des valeurs numériques littérales. On pourra par exemple écrire :

byte etatFeu = ROUGE;

Mais le compilateur ne va pas associer des valeurs arbitraires à ces constantes. La règle est de commencer à 0 et d’augmenter de 1 pour chacune des constantes qui suivent. Ainsi VERT a pour valeur 0, JAUNE a pour valeur 1 et ROUGE a pour valeur 2. Ne vous reposez toutefois pas sur cette règle, l’ajout d’une constante dans l’enum ferait capoter votre programme.

Si on veut décider des valeurs à la place du compilateur, on peut le faire pour tout ou partie des constantes :

enum { VERT, JAUNE = 5, ROUGE };

Ici, le compilateur décide des valeurs de VERT et ROUGE mais la valeur de JAUNE est fixée par nos soins. VERT aura la valeur 0 et ROUGE la valeur 6, la règle qui consiste à augmenter de 1 la valeur précédente s’appliquant toujours.

En spécifiant les valeurs des constantes dans un enum vous perdez l’assurance que les valeurs des constantes sont différentes. Si par exemple vous écrivez :
 
enum { VERT, JAUNE = 5, ROUGE = 5};
 
le compilateur ne vous dira rien et vous aurez déclaré deux constantes de noms différents et de même valeur alors que ce n’était peut être pas l’intention.

On peut dans la foulée déclarer à la fois une enum et une variable, comme ceci :

enum { VERT, JAUNE, ROUGE } etatFeu;

Contrairement aux apparences, etatFeu n’est pas une variable d’un type particulier qui ne pourrait prendre que les valeurs VERT, JAUNE et ROUGE. Non, etatFeu est un simple int et on pourra donc lui affecter n’importe quelle valeur. Cette écriture est donc un simple raccourci.

Comme une variable déclarée sous cette forme est un int, elle occupe 2 octets. C’est un peu dispendieux pour un Arduino, surtout que ces variables sont utilisées pour stocker très peu de valeurs différentes. Un byte suffit donc et on s’en tiendra à une déclaration d’enum anonyme et, séparément, d’une variable de type byte par mesure d’économie de mémoire. Comme ceci :

enum { VERT, JAUNE, ROUGE };

byte etatFeu = ROUGE;

On peut également nommer l’enum comme ceci :

enum CouleurFeu { VERT, JAUNE, ROUGE };

Ce qui permet de l’utiliser ensuite pour déclarer des variables :

enum CouleurFeu etatFeu;

Ceci est équivalent à ce que nous avons vu précédemment et par conséquent etatFeu est un int avec le même problème d’encombrement.

[1sur les Uno, Nano, Pro Mini. Le Mega dispose de 16ko.