Le Préprocesseur
Sujets abordés: Préprocesseur –Qu’est ce? –Qu’est ce qu’une directive? Les macros –Les définir, les redéfinir, les dé-définir –Les macros à arguments Directives ifdef et ifndef Autres diectives
Le préprocesseur Simple substitution de texte Augmente la lisibilité du code source Augmente la vitesse d’exécution du programme Favorise un débuggage heureux
Directives Une directive au préprocesseur commence toujours par # #include, #define, #ifdef… Les directives sont effectives sur tout le fichier.
Macros Définies par la directive #define Deux formes: –Simple remplacement d’une chaîne de caractère. –Remplacement de la chaîne et substitution d’argument. Une macro peut être définie sur plusieurs lignes (retour chariot)
Macro simple #define IDENTIFIANT chaîne chaîne est une séquence de caractères Toute occurrence de IDENTIFIANT dans le texte sera remplacé par chaîne Pas de remplacement dans entre ``
Macro simple (2) Code original #define TAXE net=brut-(brut*TAXE); printf(``TAXE\n``); Code intermédiare:... net=brut-(brut*0.7); printf(``TAXE\n``);
Macro avec arguments #define IDENTIFIANT(x,y) chaîne Pas d’espace entre IDENTIFIANT et la parenthèse x et y sont des arguments formels pour la macro Code original: #define READINT(I) scanf(``%d``,&I) … READINT(hours); Code intermédiaire: … scanf(``%d``,&hours);
Macros prédéfinies Dans stdio.h –#define getchar() getc(stdin) –#define putchar(c) putc(c,stdout)
Macro à arguments multiples Code original: #define MIN(X,Y) ( (X)>(Y) ? (X) : (Y) ) …. MIN(a,b); Code intermédiaire: …. ( (a) > (b) ? (a) : (b) )
Problèmes courants Code original: #define SQR(X) X*X … SQR(a+1); Code intermédiaire: … a+1*a+1; //ce qui est égal à a+(1*a)+1 Solution: parenthèser: #define SQR(X) (X)*(X)
Les macros ne sont pas des fonctions Code original: #define SWAP(X Y) {int temp; temp=X; X=Y; Y=temp;} void main(int){ int a=3, b=4; SWAP(a,b); } Code intermédiaire: void main(void){ int a=3,b=4; {int temp; temp=a; a=b; b=temp;} }
Macro prédéfinies __FILE__ : nom du fichier source courant __LINE__ : numéro de ligne courant __DATE__ : date de compilation du fichier courant __TIME__ : heure de compilation du fichier courant printf(``%s a été compilé le %s\n``,__FILE__,__DATE__);
Opérateurs de Macro # permet de convertir l’argument en chaîne de caractère #define MSG(F) printf(#F) … MSG(test mess); //devient printf(``test mess``); ## permet de concaténer #define ERR(X,Y) printf(X ## Y) … ERR(``err: ``,``une erreur``); //devient printf(``err: une erreur``);
Dédéfinir et redéfinir des macros Il n’est pas permis de redéfinir des macros, sauf si elles ont été dédéfinies par #undef au préalable. #undef est ignoré si l’identifiant n’a pas été défini #undef peut dédéfinir des macro prédéfinies!!!!
Inclure des fichiers On inclue des fichiers textes par #include Le texte du fichier est alors recopié à cet endroit. #include stdio.h cherche dans le chemin standard le fichier stdio.h #include ``monFichier.h`` cherche le fichier monFichier.h dans le répertoire courant.
Conséquence des inclusions #include stdio.h typedef int *p_int; prog1.h #include ``prog1.h`` Int main(void){ } prog1.c Prog1.c pourra alors utiliser les fonctions de la bibliothèque stdio.h
Compilation conditionnelle Sélectionne des parties du code à omettre lors de la compilation si une condition est remplie. Ces parties peuvent contenir des déclarations et/ou des actions Qui sont spécifique à un matériel Utiles au débuggage uniquement.
Compilation conditionnelle (2) Utiliser les directives: #ifdef, #elif, #else, #endif Les conditions de test –Sont des constantes entières –Evaluées comme Vrai/Faux –Peuvent contenir des opérateurs si ils sont évalués sur des constantes entières
Compilation conditionnelle (3) #include stdio.h #define DEBUG 2 int main(void){ #if DEBUG ==2 printf(``DEBUG est à 2\n``); #else printf(``DEBUG n’est pas à 2\n``); #endif return 0; }
Compilation conditionnelle (4) Si on effectue gcc –E fichier.c, on obtient le résultat de l’action du préprocesseur: int main(void){ printf(``DEBUG est à 2\n``); return 0; }
Compilation conditionnelle (5) Aide au débuggage d’un programme On peut donner n’importe quel nom aux identifiants Chaque directive #if doit recevoir une directive #endif
Définitions Concerne les directives #ifdef et #ifndef Utilisées pour déterminer si un symbole est connu du préprocesseur. –#ifdef identifieur vérifie si identifieur a été défini –#ifndef identifieur vérifie si il n’a pas été défini.
Combinons définitions et compilation conditionnelle Permet d’éviter de définir plusieurs fois le même identifiant ou symbole et de résoudre des conflits quand Insertion multiple d’un même fichier d’en- tête Déclaration multiple d’un identifiant Redéfinition d’un identifiant
Technique Pour un fichier en-tête classic.h: #ifndef CLASSIC.H #define CLASSIC.H …. #endif
Autre directives #error ``message`` Emet une erreur de compilation avec pour message message si activée. #line numero_de_ligne ``nom_de_fichier`` –__LINE__ est réinitialisé à numero_de_ligne –__FILE__ est réinitialisé à nom_de_fichier