6.5. Problèmes syntaxiques relatifs à la compilation séparée
Pour que le compilateur puisse compiler les fichiers séparément, il faut que vous respectiez les conditions suivantes :
• chaque type ou variable utilisé doit être déclaré ;
• toute fonction non déclarée doit renvoyer un entier (en C seulement, en C++, l'utilisation d'une fonction non déclarée génère une erreur).
Ces conditions ont des répercussions sur la syntaxe des programmes. Elles seront vues dans les paragraphes suivants.
6.5.1. Déclaration des types
Les types doivent toujours être définis avant toute utilisation dans un fichier source. Par exemple, il est interdit d'utiliser une structure client sans l'avoir définie avant sa première utilisation. Toutefois, il est possible d'utiliser un pointeur sur un type de donnée sans l'avoir complètement défini. Une simple déclaration du type de base du pointeur suffit en effet dans ce cas là. De même, un simple class MaClasse suffit en C++ pour déclarer une classe sans la définir complètement.
6.5.2. Déclaration des variables
Les variables qui sont définies dans un autre fichier doivent être déclarées avant leur première utilisation. Pour cela, on les spécifie comme étant des variables externes, avec le mot clé extern :
extern int i; /* i est un entier qui est déclaré et
créé dans un autre fichier.
Ici, il est simplement déclaré.
*/
Inversement, si une variable ne doit pas être accédée par un autre module, il faut déclarer cette variable statique. Ainsi, même si un autre fichier utilise le mot clé extern, il ne pourra pas y accéder.
6.5.3. Déclaration des fonctions
Lorsqu'une fonction se trouve définie dans un autre fichier, il est nécessaire de la déclarer. Pour cela, il suffit de donner sa déclaration (le mot clé extern est également utilisable, mais facultatif dans ce cas) :
int factorielle(int);
/*
factorielle est une fonction attendant comme paramètre
un entier et renvoyant une valeur entière.
Elle est définie dans un autre fichier.
*/
Les fonctions inline doivent impérativement être définies dans les fichiers où elles sont utilisées, puisqu'en théorie, elles sont recopiées dans les fonctions qui les utilisent. Cela implique de placer leur définition dans les fichiers d'en-tête .h ou .hpp. Comme le code des fonctions inline est normalement inclus dans le code des fonctions qui les utilisent, les fichiers d'en-tête contenant du code inline peuvent être compilés séparément sans que ces fonctions ne soient définies plusieurs fois. Par conséquent, l'éditeur de liens ne générera pas d'erreur (alors qu'il l'aurait fait si on avait placé le code d'une fonction non inline dans un fichier d'en-tête inclus dans plusieurs fichiers sources .c ou .cpp). Certains programmeurs considèrent qu'il n'est pas bon de placer des définitions de fonctions dans des fichiers d'en-tête, il placent donc toutes leurs fonctions inline dans des fichiers portant l'extension .inl. Ces fichiers sont ensuite inclus soit dans les fichiers d'en-tête .h, soit dans les fichiers .c ou .cpp qui utilisent les fonctions inline.
6.5.4. Directives d'édition de liens
Le langage C++ donne la possibilité d'appeler des fonctions et d'utiliser des variables qui proviennent d'un module écrit dans un autre langage. Pour permettre cela, il dispose de directives permettant d'indiquer comment l'édition de liens doit être faite. La syntaxe permettant de réaliser cela utilise le mot clé extern, avec le nom du langage entre guillemets. Cette directive d'édition de liens doit précéder les déclarations de variables et de données concernées. Si plusieurs variables ou fonctions utilisent la même directive, elles peuvent être regroupées dans un bloc délimité par des accolades, avec la directive d'édition de liens placée juste avant ce bloc. La syntaxe est donc la suivante :
extern "langage" [déclaration | {
déclaration
[...]
}]
Cependant, les seuls langages qu'une implémentation doit obligatoirement supporter sont les langages « C » et « C++ ». Pour les autres langages, aucune norme n'est définie et les directives d'édition de liens sont dépendantes de l'implémentation.
Exemple 6-4. Déclarations utilisables en C et en C++
#ifdef __cplusplus
extern "C"
{
#endif
extern int EntierC;
int FonctionC(void);
#ifdef __cplusplus
}
#endif
Dans l'exemple précédent, la compilation conditionnelle est utilisée pour n'utiliser la directive d'édition de liens que si le code est compilé en C++. Si c'est le cas, la variable EntierC et la fonction FonctionC sont déclarées au compilateur C++ comme étant des objets provenant d'un module C.