« Programmation C++/Le préprocesseur » : différence entre les versions

Contenu supprimé Contenu ajouté
source cpp
Ligne 9 :
Le nom du fichier peut être écrit entre guillemets <code>"''nom_du_fichier''"</code> ou entre chevrons <code>&lt;''nom_du_fichier''&gt;</code>. Dans le premier cas, cela signifie que le fichier a été écrit par le programmeur et qu'il se trouve dans le même dossier que le fichier source, dans le deuxième cas, il s'agit d'un fichier écrit par l'éditeur du compilateur.<br/>
'''Exemple : '''<br/>
<source lang="cpp">
#include <iostream>
#include <iostream>
</source>
Le fichier C++ standard iostream est inclus à cet endroit-là dans le code. Il contient la définition de certains objets standards notamment cin et cout.
 
=== #define, #undef ===
La directive <code>#define</code> permet de remplacer toutes les occurrences d'un certain mot par un autre. Par exemple :
<source lang="cpp">
#define N 1143
#define N 1143
</source>
Sur cet exemple toutes les occurrences de N seront remplacées par <code>1143</code>. Cela est parfois utilisé pour définir des constantes. On préférera toutefois utiliser le mot-clé <code>const</code>.
 
On peut très bien ne pas fixer de valeur et écrire :
<source lang="cpp">
#define PLATEFORME_INTEL
#define PLATEFORME_INTEL
</source>
La variable de compilation <code>PLATEFORME_INTEL</code> est ici définie. Combiné à <code>#ifdef</code>, on pourra compiler ou non certaines parties du code à certains endroits du programme.
 
De la même façon que l'on peut définir une variable, on peut arrêter une définition en utilisant <code>#undef</code>. Son utilisation est rare, mais peut servir à ne plus définir une variable de compilation. Par exemple:
<source lang="cpp">
#undef PLATEFORME_INTEL
#undef PLATEFORME_INTEL
</source>
 
=== #ifdef, #ifndef, #if, #endif et #else ===
Ligne 50 ⟶ 58 :
===== Exemple 1 =====
 
<source lang="cpp">
#include <iostream>
#include <iostream>
using namespace std;
using namespace std;
#define FRENCH
#define FRENCH
 
int main()
int main()
{
{
#ifdef FRENCH
#ifdef FRENCH
cout << "BONJOUR";
cout << "BONJOUR";
#else
#else
cout << "HELLO";
cout << "HELLO";
#endif
#endif
return 0;
return 0;
}
}
</source>
 
Dans ce programme, il suffit d'effacer <code>#define FRENCH</code> et de recompiler le programme pour passer d'une version française à une version anglaise. Ceci pourrait être utile si le programme comporte 10 000 lignes (ce qui est faible pour un programme réel). Bien évidemment, il existe bien d'autres façons de gérer le multilinguisme en C++.
 
===== Exemple 2 =====
 
// Définir la taille d'un tableau contenant le prix :
<source lang="cpp">
// - de 5 variétés d'orange
// Définir la taille d'un tableau contenant le prix :
#define N_ORANGES 5
// - de 35 variétés de pommesd'orange
#define N_POMMESN_ORANGES 35
// - de 3 variétés de pommes
#define N_POMMES 3

#define N_TOTAL_FRUITS N_ORANGES+N_POMMES
 
double prix_fruits[N_TOTAL_FRUITS];
 
#if N_TOTAL_FRUITS > 7
// ... plus de 7 variétés de fruits
#else
// ... moins de 7 variétés de fruits
#endif
</source>
 
===== Exemple 3 =====
'''Fichier toto.h'''<br/>
 
<source lang="cpp">
#ifndef TOTO_H
#defineifndef TOTO_H
#define TOTO_H
 
''... écrire ici les prototypes''
''... écrire ici les prototypes''
 
#endif
#endif
</source>
 
'''Le problème : ''' <br/>
Ligne 102 ⟶ 117 :
===== Autre solution =====
Toutefois, il existe une autre solution au problème précédent en utilisant la directive suivante en début de fichier <code>.h</code> :
<source lang="cpp">
#pragma once
#pragma once
</source>
Cette directive indique au compilateur d'ignorer le fichier s'il a déjà été "visité", et ne fonctionne qu'avec certains compilateurs :
* Visual C++
Ligne 112 ⟶ 129 :
Les macros sont des <code>#define</code> particulier parce qu'ils contiennent des paramètres. Ainsi si vous écrivez :
 
<source lang="cpp">
#define AFFICHE(x) cout << x << endl;
#define AFFICHE(x) cout << x << endl;
</source>
 
Alors vous pouvez écrire <code>AFFICHE("BONJOUR")</code> et le préprocesseur modifiera cette ligne et la transformera en <code>cout &lt;&lt; "BONJOUR" &lt;&lt; endl;</code>. Il y aura substitution de <code>x</code> par <code>"BONJOUR"</code>. Il ne faut pas abuser des macros et très souvent l'utilisation de fonctions, notamment les fonctions inline, est préférable.
 
==== Exemple ====
 
#include <iostream>
<source lang="cpp">
using namespace std;
#include <iostream>
using namespace std;
#define AFFICHER(x) cout << x << endl;
 
#define AFFICHER(x) cout << x << endl;
int main()
 
{
int main()
AFFICHER("BONJOUR")
{
return 0;
AFFICHER("BONJOUR")
}
return 0;
}
</source>
 
==== Bonnes pratiques ====
Afin d'utiliser correctement les macros, il est préférable de les afficher clairement et de les rendre suffisamment flexible à différentes utilisations.
Si la macros est constituée de plusieurs instructions séparés par des <code>;</code>, il est préférable d'écrire la macro sur plusieurs lignes afin d'accroître sa lisibilité. Pour indiquer à une macro que sa définition continue sur la ligne suivante, il suffit d'indiquer un antislash en fin de ligne.
<source lang="cpp">
#define AFFICHER(x) \
#define AFFICHER(x) \
cout << x; \
cout << endlx; \
cout << endl;
</source>
 
L'utilisation la plus courante des macros est de ne pas mettre de <code>;</code> à la fin de celle-ci, mais de le mettre dans le code, là où elle est utilisée. En effet, on peut prévoir qu'une macro soit utilisable en tant qu'instruction simple, ou en tant que condition ou paramètre de fonction où l'on ne doit pas mettre de <code>;</code>. Pour les macros qui ne retournent rien (comme la macro AFFICHER dans l'exemple précédent), le placement du <code>;</code> n'est pas un problème car elles ne retournent rien et ne seront jamais utilisées dans une condition ou un appel de fonction.
<source lang="cpp">
#include <iostream>
#include <iostream>
using namespace std;
using namespace std;
 
#define DIVISER(x, y) ((x) / (y))
#define DIVISER(x, y) ((x) / (y))
 
int main()
int main()
{
{
int valeur = DIVISER(5, 3);
int valeur = DIVISER(5, 3);
 
if (DIVISER(8, 2) == 4)
if (DIVISER(8, 2) == 4)
cout << DIVISER(1.0, 5.0) << endl;
 
return 0;
}
</source>
 
Il est fortement conseillé de toujours utiliser un paramètre de macro avec des parenthèses autour. Si l'on reprend l'exemple précédent sans parenthèse:
<source lang="cpp">
#include <iostream>
#include <iostream>
using namespace std;
using namespace std;
 
#define DIVISER(x, y) x / y
#define DIVISER(x, y) x / y
 
int main()
int main()
{
{
int valeur = DIVISER(5, 3);
int valeur = DIVISER(5, 3);
 
if (DIVISER(4 + 4, 2) == 4)
if (DIVISER(4 + cout << DIVISER(1.04, 5.02) <<== endl;4)
cout << DIVISER(1.0, 5.0) << endl;
 
return 0;
return 0;
}
}
</source>
 
Ici, le résultat obtenu n'est pas forcement celui désiré. <code>DIVISER(4 + 4, 2)</code> sera traduit après la précompilation par <code>4 + 4 / 2</code>. Ceci donne pour valeur 4 + 2, soit 6. Ajouter un maximum de parenthèses permet de s'assurer de la validité de la macro sous plusieurs utilisations différentes. Ainsi, dans l'exemple précédent, une utilisation de parenthèses dans la macro (<code>#define DIVISER(x, y) ((x) / (y))</code>), aurait traduit <code>DIVISER(4 + 4, 2)</code> en <code>((4 + 4) / (2)</code>. Ceci aurait donné comme valeur 8 / 2 = 4, la valeur attendue.