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é.
Trois façons de déclarer des constantes
.
Par :
DIFFICULTÉ :★☆☆
Déclaration avec le mot-clé const
Nous y avons vu la déclaration d’une constante sous cette forme :
const byte pinDEL = 10;
Où 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 unenum
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.
[1] sur les Uno, Nano, Pro Mini. Le Mega dispose de 16ko.