• Aucun résultat trouvé

Langage C avancé Utilisation du préprocesseur cpp

N/A
N/A
Protected

Academic year: 2022

Partager "Langage C avancé Utilisation du préprocesseur cpp"

Copied!
23
0
0

Texte intégral

(1)

Langage C avancé

Utilisation du préprocesseur cpp

Samuel KOKH

[email protected]

MACS 1 – Institut Galilée

(2)

Le préprocesseur cpp

Qu’est-ce que le préprocesseur (preprocessor)

Le préprocesseur est un programme qui effectue des modifications syntaxiques dans les fichiers sources de manière automatique.

shell

$ w h i c h cpp / usr / bin / cpp

(3)

Appel du préprocesseur

Appels encapsulés dans les appels à gcc (usage courant) shell

$ gcc - W a l l - c A . c

Lance le préprocesseur sur le fichier A.c et compile le résultat.

Appel « à la main » (éventuellement utile pour du débuggage) Affichage du résulat sur la sortie standard

$ cpp A . c

Envoie du résultat dans un fichier via un pipe

(4)

Comment expliquer au préprocesseur ce qu’il doit faire ?

Utilisation de «directives» préprocesseurs. Les directives commencent toujours par le caractère #.

(5)

Remplacement de texte (macros)

Code source 1 # d e f i n e L I N E S I Z E 1 0 2 4

2

3 c h a r b u f f e r[L I N E S I Z E];

4 s n p r i n t f(buffer, L I N E S I Z E, " h e l l o \ n " );

Code source apres traitement par cpp 1

2

3 c h a r b u f f e r[ 1 0 2 4 ] ;

4 s n p r i n t f(buffer, 1024 , " h e l l o \ n " );

(6)

Exemple d’utilisation des macros

1 # d e f i n e T R U E ( 1 = = 1 ) 2 # d e f i n e F A L S E ( 0 = = 1 ) 3

4 if (t e s t==T R U E){

5 D o S o m e t h i n g 6 }

Code source apres traitement par cpp 1 /* e x t r a i t du f i c h i e r m a t h . h */

2 # d e f i n e M _ P I 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 /* pi */

3

4 /* e x t r a i t du f i c h i e r s t d d e f . h */

5 # d e f i n e N U L L ((v o i d * ) 0 )

(7)

Définition de macros avec paramètres

1 # d e f i n e S Q U A R E ( a ) (( a )*( a )) 2 # d e f i n e M U L T I P L Y ( a , b ) (( a )*( b )) 3

4 d o u b l e d = S Q U A R E( 3 . 2 4 ) ;

5 d o u b l e dd = M U L T I P L Y( 3 . 2 , 4 . 5 ) ;

Code source apres traitement par cpp 1 d o u b l e d = ( ( 3 . 2 4 ) * ( 3 . 2 4 ) ) ;

2 d o u b l e dd = ( ( 3 . 2 ) * ( 4 . 5 ) ) ;

(8)

Définition de macros avec paramètres : écueils

Les macros avec paramètres peuvent être la source de très gros problèmes. Il convient par exemple de faire très attention à l’usage des parenthèses !

1 # d e f i n e S Q U A R E ( a ) a * a 2 # d e f i n e M U L T I P L Y ( a , b ) a * b 3

4 d o u b l e d = S Q U A R E(3 + 2);

5 d o u b l e dd = M U L T I P L Y(3 + 1 ,2);

Code source apres traitement par cpp 1 d o u b l e d = 3 + 2*3 + 2;

2 d o u b l e dd = 3 + 1 * 2 ;

(9)

Définition de macros avec paramètres : écueils

1 # d e f i n e min ( X , Y ) (( X ) < ( Y ) ? ( X ) : ( Y )) 2 # d e f i n e S Q U A R E ( a )*( a )

3

4 int i=3;

5 int j=0;

6 d o u b l e x = 3;

7 d o u b l e m = min(3.145 ,x);

8 d o u b l e M = min(i,j+ + ) ; 9 d o u b l e d = 1./S Q U A R E( 2 ) ;

Code source apres traitement par cpp 1 d o u b l e x = 3;

2 d o u b l e m = ( ( 3 . 1 4 5 ) < (x) ? ( 3 . 1 4 5 ) : (x));

3 d o u b l e M = ((i) < (j++) ? (i) : (j+ + ) ) ; 4 /* j est i n c r e m e n t e d e u x f o i s ! */

(10)

Inclusion de fichiers

La directive #includepermet d’inclure dans le fichier à compiler le contenu d’un autre fichier (à la manière d’un copier-coller).

1 # include< s t d i o . h >

2 # i n c l u d e " m y H e a d e r . h "

#include<>cherche les fichiers parmi une liste de directories

« système » comme /usr/local/includeou/usr/include.

#include""cherche les fichiers dans le directory local ou une liste de directories passés en argument à gcc via l’option de compilation-I, par ex. :

$ gcc -I dir1 -I dir2 -I ../dir3 -Wall -c foo.c

(11)

Compilation conditionnelle : #ifdef/#else/#endif

1 # i f d e f XXX

2 . . . . . // o p t i o n 1 3 # e l s e

4 . . . . . // o p t i o n 2 5 # e n d i f

Si XXXest défini par une directive#define alors on tient compte des lignes option 1 sinon c’est l’option 2.

1 # i f d e f E N G L I S H

2 c h a r msg[] = " h e l l o " ;

3 # e l s e

4 c h a r msg[] = " b o n j o u r " ;

5 # e n d i f

(12)

Compilation conditionnelle : #ifndef/#else/#endif

1 # i f n d e f XXX

2 . . . . . // o p t i o n 1 3 # e l s e

4 . . . . . // o p t i o n 2 5 # e n d i f

Si XXXest n’est pasdéfini par une directive #definealors on tient compte des lignes option 1 sinon c’est l’option 2.

1 # i f n d e f _ W I N 3 2

2 // _ W I N 3 2 is d e f i n e d by a l l W i n d o w s 32 c o m p i l e r s , b u t n o t by o t h e r s .

3 # i n c l u d e < u n i s t d . h >

4 # e l s e

5 # i n c l u d e < w i n d o w s . h >

6 # e n d i f

(13)

Compilation conditionnelle : les « include guards »

Tous les fichiers*.h doivent impérativement être écrits comme suit.

fichier myheader.h 1 # i f n d e f M Y _ H E A D E R _ H

2 # d e f i n e M Y _ H E A D E R _ H 3

4 ... c o n t e n u du f i c h i e r m y h e a d e r.h 5

6 # e n d i f

Ceci permet d’éviter les inclusions récursives de fichier*.h.

(14)

Compilation conditionnelle : #if//#elif#else/#endif

1 # if t e s t 1

2 . . . . . // o p t i o n 1 3 # e l i f t e s t 2

4 . . . . . // o p t i o n 2 5 # e l s e

6 . . . . . // o p t i o n 3 7 # e n d i f

test1 ettest2 sont des expressions entières évaluées par le préproceseur.

Les valeurs non-nulles sont équivalentes à « vrai » et déclenchent la compilation.

1 # if D E B U G _ L E V E L >= 2

2 p r i n t f( " a lot of d e b u g i n f o \ n " );

3 # e l i f D E B U G _ L E V E L == 1

4

(15)

Compilation conditionnelle : commenter un bloc de code

fichier myheader.h 1 # if 0

2 p r i n t f( " c e c i est un b l o c de l i g n e s " );

3 p r i n t f( " de c o d e " );

4 p r i n t f( " que je s o u h a i t e c o m m e n t e r " );

5 # e n d i f

(16)

Macros qui génèrent des instructions

Il convient d’être prudent avec les macros qui génèrent des instructions.

1 # d e f i n e E R R O R ( msg ) f p r i n t f ( stderr , msg ); e x i t ( E X I T _ F A I L U R E )

2 3

4 if(N U L L == ptr)

5 E R R O R( " p r o b l e m w i t h the p o i n t e r " );

est transformé en 1 if(N U L L == ptr)

2 f p r i n t f(stderr,msg);

3 e x i t(E X I T _ F A I L U R E);

(17)

Macros qui génèrent des instructions

Cette version ne convient pas non plus.

1 # d e f i n e E R R O R ( msg ) { f p r i n t f ( stderr , msg ); e x i t ( E X I T _ F A I L U R E )};

2

3 if(N U L L == ptr)

4 E R R O R( " p r o b l e m w i t h the p o i n t e r " );

est transformé en 1 if(N U L L == ptr){

2 f p r i n t f(stderr,msg);

3 e x i t(E X I T _ F A I L U R E);

4 };

et on ne peut pas ajouter de else 1 if(N U L L == ptr)

2 E R R O R( " p r o b l e m w i t h the p o i n t e r " );

3 e l s e {

(18)

Macros qui génèrent des instructions

La solution consiste à utiliser un do {} while(0)

1 # d e f i n e E R R O R ( msg ) do{ f p r i n t f ( stderr , msg ); e x i t ( E X I T _ F A I L U R E )}w h i l e(0)

2

3 if(N U L L == ptr)

4 E R R O R( " p r o b l e m w i t h the p o i n t e r " );

est transformé en 1 if(N U L L == ptr)

2 do {

3 f p r i n t f(stderr,msg);

4 e x i t(E X I T _ F A I L U R E);

5 } w h i l e( 0 ) ;

(19)

Scope de définition d’une macro

Le préprocesseur remplace une expression par la valeur de sa macro à partir de l’endroit où elle est définit dans le fichier.

La directive #undefpermet d’annuler la définition d’une macro.

1 bob = X;

2 # d e f i n e X 125 3 a l i c e = X; 4 p e t e r = X; 5 # u n d e f X 6 m a r y = X;

est remplacé par 1 bob = X;

2

(20)

On peut écrire les macros sur plusieurs lignes grâce au backslash.

1 # d e f i n e MSG " h e l l o \ 2 w o r l d\

3 "

4

5 # d e f i n e E R R O R ( msg ) do {\

6 f p r i n t f ( stderr , msg );\

7 e x i t ( E X I T _ F A I L U R E )}\

8 w h i l e (0) 9

10

11 p r i n t f ( MSG );

12 if ( N U L L == ptr )

13 E R R O R ( "w r o n g p o i n t e r" );

(21)

Quelques Macros prédéfinies

__DATE__: est remplacé par la date de compilation

__FILE__: est remplacé par le nom du fichier source en train d’être compilé

__LINE__: est remplacé par le numéro de ligne dans le fichier source en train d’être compilé

__TIME__: est remplacé par l’heure de compilation

(22)

Quelques Macros utiles pour le débuggage

1 # d e f i n e D I S P L A Y L I N E p r i n t f ( " DB % s : % d \ n " , _ _ F I L E _ _ , _ _ L I N E _ _ )

2

3 # d e f i n e S h o w D o u b l e ( var ) p r i n t f ( " DB % s = % g \ n " ,# var , var )

4 # d e f i n e S h o w I n t ( var ) p r i n t f ( " DB % s = % d \ n " ,# var , var )

5 # d e f i n e S h o w C h a r ( var ) p r i n t f ( " DB % s = % c \ n " ,# var , var )

6 # d e f i n e S h o w S t r i n g ( var ) p r i n t f ( " DB % s = % s \ n " ,# var , var )

(23)

Définition de macro à l’appel de gcc

Il est possible de définir ou de spécifier la valeur d’une macro à la volée, à l’appel de gcc, sans modifier les fichiers sources.

Définition de la macro myMacro

$ gcc - D m y M a c r o - W a l l - c foo . c

Définition de la valeur de la macromyMacro

$ gcc - D m y M a c r o =2 - W a l l - c foo . c

Références

Documents relatifs

CreatePages: PROCEDURE [ea: POINTER, efa: POINTER TO CFA, lastPage: PageNumber, lastBytes: CARDINAL]:. DeletePages: PROCEDURE [ea:

2/ a) montrer que le triangle ADK est rectangle et isocèle. b) déterminer la nature et les éléments caractéristiques de f. Soit I et J les milieux respectifs de [OA] et [OB]. c)

L’experiència sobre com s’ha introduït la perspectiva de gènere al Pla per a la Inclusió i la Cohesió social de l’Alt Empordà s’ha d’analitzar tenint en compte, d’una

[r]

[r]

[r]

Soient premier et dernier les extrémités gauche et droite de l'intervalle dans lequel on cherche la valeur x, on calcule m, l'indice de l'élément médian :. m(premier + dernier) div

[r]