Nous allons découvrir maintenant une nouvelle directive de préprocesseur : le #define.
Cette directive permet de définir une
constante de préprocesseur. Cela permet d'associer une valeur à un mot. Voici un exemple :
Code : C | #define NOMBRE_VIES_INITIALES 3
|
Vous mettez dans l'ordre :
- le #define
- le mot auquel la valeur va être associée
- la valeur du mot
Attention, malgré les apparences (notamment le nom que l'on a l'habitude de mettre en majuscules) c'est
très différent des constantes que nous avons étudiées jusqu'ici, telles que :
Code : C | const int NOMBRE_VIES_INITIALES = 3;
|
Les constantes occupaient de la place en mémoire. Même si la valeur ne changeait pas, votre nombre "3" était stocké quelque part dans la mémoire.
Ce n'est pas le cas des constantes de préprocesseur
Comment ça fonctionne ? En fait, le #define remplace dans votre code source tous les mots par leur valeur correspondante. C'est comme la fonction "rechercher / remplacer" de Word si vous voulez

Ainsi, la ligne :
Code : C | #define NOMBRE_VIES_INITIALES 3
|
... remplace dans le fichier chaque NOMBRE_VIES_INITIALES par 3.
Voici un exemple de fichier .c avant passage du préprocesseur :
Code : C | #define NOMBRE_VIES_INITIALES 3
int main(int argc, char *argv[])
{
int vies = NOMBRE_VIES_INITIALES;
/* Code ...*/
|
Après passage du préprocesseur :
Code : C | int main(int argc, char *argv[])
{
int vies = 3;
/* Code ...*/
|
Avant la compilation, tous les #define auront donc été remplacés par les valeurs correspondantes. Le compilateur "voit" le fichier après passage du préprocesseur, dans lequel tous les remplacements auront été effectués.
Quel intérêt par rapport à l'utilisation de constantes comme on l'a vu jusqu'ici ?
Eh bien, comme je vous l'ai dit ça
ne prend pas de place en mémoire. C'est logique, vu que lors de la compilation il ne reste plus que des nombres dans le code source.
Un autre intérêt est que le remplacement se fait dans
tout le fichier dans lequel se trouve le #define. Si vous aviez défini une constante en mémoire dans une fonction, celle-ci n'aurait été valable que dans la fonction puis aurait été supprimée. Le #define en revanche s'appliquera à toutes les fonctions du fichier, ce qui peut s'avérer vraiment pratique pour le programmeur.
Un exemple concret d'utilisation des #define ?
En voici un que vous ne tarderez pas à utiliser. Lorsque vous ouvrirez une fenêtre en C, vous aurez probablement envie de définir des constantes de préprocesseur pour indiquer les dimensions de la fenêtre :
Code : C | #define LARGEUR_FENETRE 800
#define HAUTEUR_FENETRE 600
|
L'avantage est que si plus tard vous décidez de changer la taille de la fenêtre (parce que ça vous semble trop petit), il vous suffira de modifier les #define puis de recompiler.
A noter : les #define sont généralement placés dans des .h, à côté des prototypes (vous pouvez d'ailleurs aller voir les .h des bibliothèques comme stdlib.h, vous verrez qu'il y a des #define !).
Les #define sont donc "faciles d'accès", vous pouvez changer les dimensions de la fenêtre en modifiant les #define plutôt que d'aller chercher au fond de vos fonctions l'endroit où vous ouvrez la fenêtre pour modifier les dimensions. C'est donc du temps de gagné pour le programmeur
En résumé, les constantes de préprocesseur permettent de "configurer" votre programme avant sa compilation. C'est une sorte de mini-configuration en fait
Un define pour la taille des tableaux
On utilise souvent les defines pour définir la taille des tableaux. On fait par exemple :
Code : C | #define TAILLE_MAX 1000
int main(int argc, char *argv[])
{
char chaine1[TAILLE_MAX], chaine2[TAILLE_MAX];
// ...
|
Mais... Je croyais qu'on ne pouvait pas mettre de variable entre les crochets lors d'une définition de tableau ?
Oui, mais TAILLE_MAX n'est PAS une variable

En effet je vous l'ai dit, le préprocesseur transforme le fichier avant compilation en :
Code : C | int main(int argc, char *argv[])
{
char chaine1[1000], chaine2[1000];
// ...
|
... et cela est valide
En définissant TAILLE_MAX ainsi, vous pouvez vous en servir pour créer des tableaux d'une certaine taille. Si cela s'avère insuffisant par le futur, vous n'aurez qu'à modifier la ligne du #define, recompiler, et vos tableaux de char prendront tous la nouvelle taille que vous aurez indiquée
Calculs dans les defines
Il est possible de faire quelques petits calculs dans les defines.
Par exemple, ce code crée une constante LARGEUR_FENETRE, une autre HAUTEUR_FENETRE, puis une troisième NOMBRE_PIXELS qui contiendra le nombre de pixels affichés à l'intérieur de la fenêtre (le calcul est simple : largeur * hauteur) :
Code : C | #define LARGEUR_FENETRE 800
#define HAUTEUR_FENETRE 600
#define NOMBRE_PIXELS (LARGEUR_FENETRE * HAUTEUR_FENETRE)
|
La valeur de NOMBRE_PIXELS est remplacée avant la compilation par (LARGEUR_FENETRE * HAUTEUR_FENETRE), c'est-à-dire par (800 * 600), ce qui fait 480000

Mettez toujours votre calcul entre parenthèses comme je l'ai fait.
Vous pouvez faire toutes les opérations de base que vous connaissez : addition (+), soustraction (-), multiplication (*), division (/) et modulo (%)
Les constantes prédéfinies
En plus des constantes que vous pouvez définir vous-mêmes, il existe quelques constantes prédéfinies par le préprocesseur. A l'heure où j'écris ces lignes, je dois vous dire que je ne les ai encore jamais utilisées, mais il n'est pas impossible que vous leur en trouviez une utilité donc je vais vous les présenter
Chacune de ces constantes commence et se termine par 2 symboles underscore _ (que vous trouverez sous le chiffre 8, tout du moins si vous avez un clavier AZERTY).
- __LINE__ : donne le numéro de la ligne actuelle
- __FILE__ : donne le nom du fichier actuel
- __DATE__ : donne la date de la compilation
- __TIME__ : donne l'heure de la compilation
Je pense que ces constantes peuvent être utiles pour gérer des erreurs, en faisant par exemple ceci :
Code : C | printf("Erreur a la ligne %d du fichier %s\n", __LINE__, __FILE__);
printf("Ce fichier a ete compile le %s a %s\n", __DATE__, __TIME__);
|
Code : Console | Erreur a la ligne 9 du fichier main.c
Ce fichier a ete compile le Jan 13 2006 a 19:21:10 |
Les définitions simples
Il est aussi possible de faire tout simplement :
Code : C
... sans préciser de valeur.
Cela veut dire pour le préprocesseur que le mot CONSTANTE est défini, tout simplement. Il n'a pas de valeur, mais il "existe".
J'en vois vraiment pas l'intérêt !?
L'intérêt est moins évident que tout à l'heure, mais il y en a un et nous allons le découvrir bientôt.
