FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 27, nombre de questions : 175, dernière mise à jour : 17 décembre 2010  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.

Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .

Sur ce, je vous souhaite une bonne lecture.


SommaireCompilation et édition des liensLe préprocesseur (12)
précédent sommaire suivant
 

Avant d'être effectivement compilés, les fichiers sources sont tout d'abord traités par un programme appelé préprocesseur qui se chargera d'exécuter toutes les commandes commençant par # (#include, #define, etc.) jusqu'à ce qu'il n'y en ait plus une seule. C'est à ce moment et à ce moment seulement, c'est-à-dire après passage du préprocesseur si besoin était, que la compilation proprement dite (c'est-à-dire traduction du fichier source en fichier objet) peut enfin être lancée.

Mis à jour le 20 septembre 2004 gl Melem

#define N 10 définit une macro N que le préprocesseur devra remplacée par 10 après son passage. Cela signifie que :

Code c :
1
2
3
4
5
6
#define N 10 
  
int f(void) 
{ 
    return N + 1; 
}
Donnera après passage du préprocesseur :

Code c :
1
2
3
4
int f(void) 
{ 
    return 10 + 1; 
}

Mis à jour le 20 septembre 2004 gl

Les macros peuvent accepter des paramètres, un peu comme les fonctions. Le nom de la macro doit être immédiatement suivi (sans même un espace) de la parenthèse ouvrante, des paramètres puis de la parenthèse fermante. Vient ensuite le corps de la macro qui peut s'étaler sur plusieurs lignes, chacune sauf la dernière se terminant par un anti-slash : \. Par exemple :

Code C :
1
2
3
4
5
6
7
8
#define PRINT(x) printf("MESSAGE : %s\n", x) 
  
int main(void) 
{ 
    PRINT("Hello, world !"); 
  
    return 0; 
}
Donnera après passage du préprocesseur :

Code C :
1
2
3
4
5
6
int main(void) 
{ 
    printf("MESSAGE : %s\n", "Hello, world !"); 
  
    return 0; 
}

Mis à jour le 20 septembre 2004 gl

#define MYMACRO définit une macro MYMACRO qui sera remplacée, après passage du préprocesseur, par… rien ! Par exemple :

Code c :
1
2
3
4
5
6
7
8
9
#define IN 
#define OUT 
  
int f(IN int n, OUT int * p1, OUT int * p2) 
{ 
    *p1 = n - 1; 
    *p2 = n + 1; 
    return 2 * n; 
}
Donnera après passage du préprocesseur :

Code C :
1
2
3
4
5
6
int f( int n,  int * p1,  int * p2) 
{ 
    *p1 = n - 1; 
    *p2 = n + 1; 
    return 2 * n; 
}

Mis à jour le 20 septembre 2004 gl Melem

Le test if defined(NOM_MACRO) ou ifdef NOM_MACRO permet de savoir si une macro appelée NOM_MACRO est définie. Voici quelques exemples d'utilisation.

Code c :
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h> 
  
#if defined(UPPERCASE) 
#   define MESSAGE "HELLO, WORLD !" 
#else 
#   define MESSAGE "Hello, world !" 
#endif 
  
int main(void) 
{ 
    printf("%s\n", MESSAGE); 
    return 0; 
}
Dans cet exemple, puisque la macro UPPERCASE n'a pas été définie, tout ce qui est situé entre le test et le else sera ignoré (supprimé !) par le préprocesseur. Plus précisément, du bloc if ... else ... endif, il ne restera plus que ce qui se trouvait entre le else et le endif. Ici, MESSAGE sera donc remplacé par le préprocesseur par "Hello, world !". Si UPPERCASE avait cependant été définie, MESSAGE aurait alors été remplacé par "HELLO, WORLD !".

Mis à jour le 23 mars 2009 Melem

Il y en a plusieurs ! Voici quelques points auxquels il faut faire très bien attention lorsqu'on fait usage des macros.

Parenthèses :
Soit la macro CARRE dont le rôle est de fournir le carré de la valeur passée en paramètre. Si elle est définie de la sorte : #define CARRE(x) x * x, Son utilisation pour un paramètre tel que 9 + 1 sera erronée. En effet CARRE(9 + 1) sera remplacé par 9 + 1 * 9 + 1 qui en C est équivalent à 9 + (1 * 9) + 1, la multiplication étant prioritaire par rapport à l'addition, ce qui n'est bien entendu pas le carré de 9 + 1. Il convient donc de toujours parenthéser à l'extrême les macros, la nôtre devant s'écrire alors : #define CARRE(x) ((x) * (x)).

Effets de bord :
Soit la macro MAX fournissant le maximum de deux nombres : #define MAX(x, y) ((x) > (y) ? (x) : (y)). Appelée de la manière suivante : k = MAX(3, 2), k aura évidemment la valeur 3. Soient maintenant i et j, deux variables de type int valant toutes 2. On pense alors qu'avec k = MAX(++i, j), k aura encore la valeur 3 comme dans l'exemple précédent alors que cette fois-ci elle aura la valeur 4 ! En effet, k = MAX(++i, j) est remplacé par le préprocesseur par k = ((++i) > (j) ? (++i) : (j)). Comme i a été incrémenté deux fois, on aura k = 4 et non 3 comme il était attendu.

Nom des paramètres :
Une erreur de ce genre peut également arriver : avec #define ERR_PRINT_INT(n) fprintf(stderr, "%d\n", n), ERR_PRINT_INT(10) sera remplacé par fprintf(stderr, "%d\10", 10) !

Mis à jour le 20 septembre 2004 gl

Dans la définition d'une macro, l'opérateur # permet de transformer un argument en chaîne de caractères, quel que soit l'argument. Par exemple :

Code C :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h> 
  
#define TOSTR(x) #x 
#define NNNNN 99999  
  
int main(void) 
{ 
    printf("%s\n", TOSTR(10000)); /* --> "10000" */ 
    printf("%s\n", TOSTR(1 + 1)); /* --> "1 + 1" */ 
    printf("%s\n", TOSTR(n + 1)); /* --> "n + 1" */ 
    printf("%s\n", TOSTR(float)); /* --> "float" */ 
    printf("%s\n", TOSTR(NNNNN)); /* --> "NNNNN" */ 
  
    return 0; 
}
Comme on peut le constater, TOSTR(NNNNN) est traité par le préprocesseur comme #NNNNN et, sachant qu'il est en train de développer une macro, va remplacer cette séquence en "NNNNN" et non en "99999" ! Pour avoir "99999" au lieu de "NNNNN", on pourra utiliser l'astuce suivante :

Code C :
1
2
#define TOSTR(x) __STR(x) 
#define __STR(x) #x
Dans ce cas, au passage du préprocesseur, TOSTR(NNNNN) sera dans un premier temps remplacé par __STR(99999) qui sera à son tour (dans une deuxième passe), remplacé par "99999".

Mis à jour le 29 novembre 2004 gl Melem

Dans la définition d'une macro, l'opérateur ## permet de concaténer deux arguments. Ainsi avec : #define CAT(x, y) x##y, CAT(C, 90) sera remplacé par le préprocesseur par C90. Voici un autre exemple avec programme complet :

Code C :
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h> 
#include <wchar.h> 
  
#define WIDESTR(x) L##x 
#define AU_REVOIR "Au revoir" 
  
int main(void) 
{ 
    wprintf(WIDESTR("%s\n"), WIDESTR("Bonjour")); /* --> wprintf(L"%s\n", L"Bonjour"); */ 
  
    return 0; 
}
Par contre, WIDESTR(AU_REVOIRE) sera traité par le préprocesseur comme L##AU_REVOIR et, sachant qu'il est en train de développer une macro, va remplacer cette séquence en LAU_REVOIR et non en L"Au revoir" ! Pour avoir L"Au revoir" au lieu de LAU_REVOIR, on pourra utiliser l'astuce suivante :

Code C :
1
2
#define WIDESTR(x) ___WSTR(x) 
#define ___WSTR(x) L##x
Dans ce cas, au passage du préprocesseur, WIDESTR(AU_REVOIR) sera dans un premier temps remplacé par ___WSTR("Au revoir") qui sera à son tour (dans une deuxième passe), remplacé par L"Au revoir".

Mis à jour le 29 novembre 2004 Laurent Gomila Melem

La directive pragma permet d'envoyer une commande (par exemple une option de compilation, d'édition des liens, etc.) au compilateur. Ces commandes sont toutefois spécifiques au compilateur. La norme requiert que lorsque le compilateur ne reconnaît pas une commande, il doit tout simplement l'ignorer (les compilateurs émettent généralement un warning pour informer l'utilisateur de ce fait).

Mis à jour le 27 juillet 2008 Melem

La directive error permet d'interrompre la compilation, comme si une erreur s'était produite. Par exemple, pour faire une source qui ne puisse compiler que si la taille d'un char sur la cible est de 8 bits, on peut faire :

Code C :
1
2
3
4
5
6
#include <limits.h> 
... 
#if (CHAR_BIT != 8) 
#   error Ce programme requiert que la taille d'un char soit de 8 bits. 
#endif 
...

Mis à jour le 27 juillet 2008 Melem

Quelle est la taille d'un char ?

Non car sizeof (...) est évaluée pendant la compilation, pas avant. L'astuce suivante permet de générer une véritable erreur de compilation lorsqu'un test échoue (ici, on va générer une erreur lorsque sizeof(int) est différent de sizeof(long)).

Code C :
1
2
3
/* Si sizeof(int) != sizeof(long), le tableau assert_int_long aura une taille négative, */ 
/* ce qui ne sera pas apprécié par le compilateur ...                                   */ 
static int assert_int_long[sizeof(int) == sizeof(long) ? 1 : -1];

Mis à jour le 27 juillet 2008 gege2061 Melem

__DATE__ est une macro, elle est remplacée par le préprocesseur par la date de compilation du fichier. Elle est donc traitée par le préprocesseur, pas évaluée à l'exécution.

Mis à jour le 20 septembre 2004 gl

Comment obtenir la date et l'heure courante ?

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
 
 
 
Partenaires

PlanetHoster
Ikoula