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écifiques à un matériel
• Utiles au débuggage uniquement.
Compilation conditionnelle (2)
•
Utiliser les directives:
#if, #ifdef, #elif, #else, #endif
•
Les conditions de test
•
Sont sur des constantes entières
•
Evaluées comme Vrai/Faux
•
Peuvent contenir des opérateurs s ’ 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;
}
•
L ’ option –E permet d ’ appeler le préprocesseur
mais n ’ effectue pas la compilation.
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 identificateur vérifie si identificateur a été défini
• #ifndef identificateur vérifie si il n’a pas été défini
•
Une directive par ligne
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 il y a :
• Insertion multiple d’un même fichier d’en-tête
• Déclaration multiple d’un identifiant
• Redéfinition d’un identifiant
•
Pour un fichier entê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
•
Une ligne de la forme # n ’ a aucun effet
Fonctions à arguments variables
• La norme ANSI définit des mécanismes permettant de traiter de façon portable des listes d'arguments variables telles qu'on en trouve par exemple dans les fonctions
printf et scanf
int printf (const char *format, ...);
• Pour pouvoir traiter des listes d'arguments variables, il faut inclure le fichier stdarg.h :
#include <stdarg.h>
Fonctions à arguments variables
• On dispose alors d'un type, va_list, et de trois macros sur des objets de ce type : va_arg, va_end et va_start.
• va_start initialise une liste d’arguments variable. Elle prend en paramètre la liste et le dernier paramètre de la fonction avant le début de la liste.
(donc les listes d’arguments variables sont toujours à la fin des paramètres)
• va_end doit être appelée obligatoirement avant le retour de la fonction.
Elle prend la liste en paramètre.
• va_arg permet d’accéder à l’élément courant de la liste. Elle prend en paramètre la liste et un nom de type (celui de l’élément courant).
Fonctions à arguments variables
• Exemple :
• Soit une fonction qui doit calculer la somme d'une liste variable de nombres entiers, le nombre exact de nombres à additionner étant fourni en paramètre. L'entête de la fonction s'écrit :
int somme (int n, ...)
• Les trois points "..." indiquent que la fonction admet une liste d'arguments variable
Fonctions à arguments variables
• Dans cette fonction il faut alors déclarer une variable de type va_list, en fait une variable qui va pointer sur les différents arguments de la liste :
int somme (int n, ...) { va_list liste; ...}
• La variable de type va_list doit être initialisée à l'aide de l'opération va_start qui a besoin pour cela du
paramètre qui précède la liste d'arguments variable :
int somme (int n, ...) { va_list liste;
va_start (liste, n); ...
}
Fonctions à arguments variables
• On peut ensuite accéder successivement aux différents arguments de la liste d'arguments variables à l'aide de la macro va_arg qui retourne à chaque fois l'argument
pointé par liste et fait pointer celle-ci sur l'argument suivant.
• Enfin, quand elle a fini son traitement, la fonction doit utiliser l'opération va_end pour clore l'accès à la liste d'arguments variable.
Fonctions à arguments variables
int somme (int n, ...) {
va_list liste;
int cpt, resultat=0;
va_start (liste, n);
for (cpt= 0; cpt< n; cpt++)
resultat += va_arg (liste, int);
va_end(liste);
return resultat;
}
Déclaration de la liste d’arguments Initialisation de la liste sur l’élément qui suit n
Accès au 1er
élément de la liste Accès au 2ème élément de la liste Accès au 3ème élément de la liste … Fin d’utilisation de la liste
Fonctions à arguments variables
• Exemple d’appel :
• somme (4,1,2,3,4);
Fonctions à arguments variables
• Question :
• Est-il possible d’écrire une fonction qui ne prend qu’une liste d’arguments variables ?
int f(…)
Exercices
• Concevoir une fonction "moyenne" qui calcule la moyenne d'un nombre n donné mais variable de réels.
• Concevoir une fonction "concaténation" qui concatène un nombre n donné mais variable de chaînes de caractères et les stocke dans une chaîne destination.
Solution 1
#include <stdio.h>
#include <stdarg.h>
/* n : le nombre de reels dans la liste d'arguments variable ... : une liste d'arguments de type double variable
Resultat : la moyenne des reels de la liste d'arguments variable */
double moyenne (int n, ...) {
va_list listeReels; int cptrArgs; double somme;
va_start (listeReels, n);
for (somme = cptrArgs = 0; cptrArgs < n; cptrArgs++) somme += va_arg (listeReels, double);
va_end (listeReels);
return (n != 0) ? (somme / n) : 0;
}
Solution 1
/* Le programme de test */
int main() {
printf("moyenne(2, 4.0, 6.0) = %f\n", moyenne(2, 4.0, 6.0));
printf("moyenne(4, 4.5, 6.0, 7.25, 8.75) = %f\n", moyenne(4, 4.5, 6.0, 7.25, 8.75));
printf("moyenne(0) = %f\n", moyenne(0));
}
Solution 2
• Comme il faut d'abord connaître la taille de la chaîne destination, il faut traiter deux fois la liste d'arguments
variable, une fois pour calculer la taille de la destination et une deuxième fois pour y stocker les chaînes.
• #include <stdio.h>
• #include <string.h>
• #include <stdarg.h>
• /* La fonction concat Arguments : n : le nombre de
chaines dans la liste d'arguments variable ... : une liste d'arguments de type char * variable
• Resultat : la concatenation des chaines */
Solution 2
char *concat (int n, char* resultat, size_t taille_max, ...) { va_list liste; int cpt; char* chaine;
size_t taille=strlen(resultat);
va_start(liste, taille_max);
for (cpt = 0; cpt < n; cpt++) { chaine=va_arg(liste, char*);
if (taille+strlen(chaine)<=taille_max) strcat(resultat, chaine);
else{
strncat (resultat, chaine, taille_max-taille);
taille=taille_max;
break;
}
taille+=strlen(chaine);
}
resultat[taille]=‘\0’;
va_end(liste);
return resultat;
}
Solution 2
int main(int argc, char* argv[]){!
char* s = (char*) malloc(50); !
s=concat(4, s, 49, "ceci", "est", "un", "test");!
printf("s=%s\n",s);!
s=concat(10, s, 49, "ceci", "est", "un", ! "nouveau", "test", "un", "peu", "plus”,!
"long", "colle a la suite de l'autre chaine");!
printf("s=%s\n",s);!
free(s);!
return EXIT_SUCCESS;!
}!