Autres éléments du langage
Le préprocesseur Le préprocesseur transforme le texte source d'un programme avant que la compilation ne commence. Le préprocesseur est un programme séparé, indépendant du compilateur. Les transformations qu'il effectue sur un programme sont: des ajouts; des suppressions; des remplacements de morceaux de texte
Directives du préprocesseur Le préprocesseur Directives du préprocesseur Les modifications textuelles sur le fichier source sont effectuées а partir de directives. Les directives destinées au préprocesseur comportent, dans l'ordre : un signe # (qui, en syntaxe originale, doit occuper la première position de la ligne) ; un mot-clé parmi include, define, if, ifdef, ifndef, else et endif qui identifie la directive. le corps de la directive, dont la structure dépend de la nature de celle-ci.
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #include Elle permet d'incorporer dans le fichier source le texte figurant dans un autre fichier (ce dernier peut être un fichier en-tête de la librairie standard (stdio.h, math.h,...) ou n'importe quel autre fichier. recherche le fichier mentionné dans le répertoire correspondant à la bibliothèque du C (sur PC dans \TC\INCLUDE) #include <nom-de-fichier> #include "nom-de-fichier" recherche le fichier mentionné dans le répertoires courant
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #include Attention. Il ne faut pas confondre inclusion de fichiers et compilation séparée. Les fichiers que l'on inclut au moyen de la directive #include contiennent du texte source C qui sera compilé chaque fois que l'inclusion sera faite (c'est pourquoi ces fichiers ne contiennent jamais de fonctions). Le service rendu par la directive #include est de permettre d'avoir un texte en un seul exemplaire, non de permettre de le compiler une seule fois.
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Elle permet de définir : des constantes symboliques; des macros avec paramètres Des constantes symboliques Substitue toute occurence de nom par la chaîne de caractères reste-de-la-ligne dans la suite du fichier source #define nom reste-de-la-ligne #define NB_LIGNES 10 #define NB_COLONNES 33 #define TAILLE_MATRICE NB_LIGNES * NB_COLONNES
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres Exemple #define nom(liste_de_paramètres) corps_de_la_macro #define permuter(a, b, type) { type w_; w_ = a; a = b; b = w_; } . . . permuter(t[i], t[j], short *); { short * w_; w_ = t[i]; t[i] = t[j]; t[j] = w_; } appel Résultat de la substitution (développement) de la macro
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres La distinction entre une définition de constante symbolique et celle d'une macro avec paramètres se fait sur le caractère qui suit immédiatement le nom de la macro : si ce caractère est une parenthèse ouvrante, c'est une macro avec paramètres, sinon c'est une constante symbolique. CARRE(2) -> 2*2 #define CARRE(a) a * a #define CARRE (a) a * a CARRE(a+b) -> a+b*a+b CARRE(2) -> (a) a * a (2)
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres Il est conseillé de toujours mettre entre parenthèses le corps de la macro et les paramètres formels. La principale utilité des macros est d'améliorer l'expressivité et la portabilité des programmes #define CARRE(a) (a * a) CARRE(a+b) -> (a+b)*(a+b) Si on ne dispose pas du type void * p = (machin *) malloc(sizeof(machin)); #define NOUVEAU(type) ((type *) malloc(sizeof(type))) p = NOUVEAU(machin);
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres Macros et Fonctions Une macro ressemble à une fonction, mais sera d'exécution plus rapide : Le corps d'une fonction figure en un seul exemplaire dans le programme exécutable dont elle fait partie Le texte macro est directement inséré (recopié puis compilé) à l'endroit voulu, mais pas de gestion de pile.
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres Macros et Fonctions Les inconvénients d’une macro: l'espace occupé; leur définition hors syntaxe les rend très dificiles à maîtriser au-delà d'un certain degré de complexité (pas de variables locales, etc.).
Directives du préprocesseur Le préprocesseur Directives du préprocesseur La directive #define Des macros avec paramètres Macros et Fonctions En faveur des macros: leur eficacité (on gagne à chaque fois le coût d'un appel de fonction); elles sont indépendantes des types de leurs arguments ou même, comme ci-dessus, elles peuvent avoir un type pour argument.
Le préprocesseur Directives du préprocesseur Compilation conditionnelle La compilation conditionnelle a pour but d'incorporer ou d'exclure des parties du code source dans le texte qui sera généré par le préprocesseur. Elle permet d'adapter le programme au matériel ou а l'environnement sur lequel il s'exécute, ou d'introduire dans le programme des instructions de débogage. Les directives de compilation conditionnelle se répartissent en deux catégories: la valeur d'une expression l'existence ou l'inexistence de symboles
Le préprocesseur Directives du préprocesseur Compilation conditionnelle Les formes des directives de conditionnelle: #ifdef identifcateur #ifndef identifcateur #if expression . . . texte compilé si la condition est vraie, ignoré si elle est fausse #else texte compilé si la condition est fausse, ignoré si elle est vraie #endif
Le préprocesseur Directives du préprocesseur Compilation conditionnelle Les formes des directives de conditionnelle: identificateur est le nom d'une macro actuellement définie #ifdef identifcateur . . . texte compilé si la condition est vraie, ignoré si elle est fausse #endif identificateur n'est pas le nom d'une macro actuellement définie #ifndef identifcateur . . . texte compilé si la condition est vraie, ignoré si elle est fausse #endif
Le préprocesseur Directives du préprocesseur Compilation conditionnelle Les formes des directives de conditionnelle: Exemples: #ifndef entier #define entier int /* si une autre bibliothèque incluse plus haut l'a déjà défini, on ne le redéfinit plus */ #endif #ifdef biblio_graphique initialise_ecran(); efface_ecran(); trace(dessin); #else puts("si on avait eu un écran graphique j'aurai fait un dessin"); /* biblio_graphique peut être défini dans un "header" (fichier.h) inclus ou non plus haut */
Le préprocesseur Directives du préprocesseur Compilation conditionnelle Les formes des directives de conditionnelle: Exemple: rajouter des instructions destinées au débogage du programme : #define DEBUG . . . #ifdef DEBUG for (i = 0; i < N; i++) printf("%d\n",i); #endif /* DEBUG */ Il suffit de supprimer la directive #define DEBUG pour que les instructions liées au débogage ne soient pas compilées.
Le préprocesseur Directives du préprocesseur Compilation conditionnelle Les formes des directives de conditionnelle: Exemple: rajouter des instructions destinées au débogage du programme : #define N 5 #include <stdio.h> #define DEBUG #ifdef DEBUG void main() { int i; for (i = 0; i < N; i++) printf("%d\n",i); } #endif /* DEBUG */ 1 2 3 4
Les arguments du programme principal Le préprocesseur Les arguments du programme principal Cette section ne concerne que les environnements, comme UNIX ou MS-DOS, dans lesquels les programmes sont activés en composant une commande de la forme: nom-du-programme argument1 ... argumentk. Lors d’appel de programme (fonction main), des arguments sont fournis au programme. int main(int argc, char *argv[ ]) l'en-tête complet de main, en syntaxe ANSI nombre d'arguments du programme Tableau des arguments du programme. Par convention, le premier argument est le nom du programme.
Les arguments du programme principal Le préprocesseur Les arguments du programme principal Un programme qui, une fois compilé, se nomme echo ; Supposons que ce programme soit lancé par la commande : echo Pierre Paul main reçoit les arguments
Les arguments du programme principal Le préprocesseur Les arguments du programme principal Supposons que tout ce que l'on demande à echo soit de recopier la liste de ses arguments. main(int argc, char *argv[ ]) { int i; for (i = 0; i < argc; i++) printf("%s\n", argv[i]); return 0; } echo Pierre Paul
Les arguments du programme principal Le préprocesseur Les arguments du programme principal La principale application de ce mécanisme est la fourniture à un programme des paramètres dont il peut dépendre, comme des noms de fichiers, des tailles de tableaux, etc. Par exemple, voici une version du programme de copie de fichiers, qui prend les noms des fichiers source et destination comme arguments. Si nous appelons copier le fichier exécutable produit en compilant le texte ci-dessus, alors nous pourrons l'exécuter en composant la commande: copier srce dest
Les arguments du programme principal Le préprocesseur Les arguments du programme principal #include <stdio.h> #define PAS_D_ERREUR 0 #define ERREUR_OUVERTURE 1 #define ERREUR_CREATION 2 #define PAS_ASSEZ_D_ARGUMENTS 3 FILE *srce, *dest; main(int argc, char *argv[]) { char tampon[512]; int nombre; if (argc < 3) return PAS_ASSEZ_D_ARGUMENTS; if ((srce = fopen(argv[1], "rb")) == NULL)return ERREUR_OUVERTURE; if ((dest = fopen(argv[2], "wb")) == NULL) return ERREUR_CREATION; while ((nombre = fread(tampon, 1, 512, srce)) > 0) fwrite(tampon, 1, nombre, dest); fclose(dest); return PAS_D_ERREUR; } Le nom du programme:com_li
Les arguments du programme principal Le préprocesseur Les arguments du programme principal com.li a b dans le Commande Prompt 11 ss sss 22 hh hhh 11 ss sss 22 hh hhh