Inclusions & dépendances
C compile texte > objet int main () …
Cas de fichiers multiples int main () { toto() } … Calltoto void toto () … Icitoto toto est inconnu Icitoto Édition de liens: résout les adresses et crée l’exécutable
La résolution des adresses se fait par le nom de l’objet float toto; …. toto=-1.0; extern int toto; Format IEEE: signe(1), exposant(8) 1.mantisse Compilation et édition de liens fonctionnent, mais l’entier toto vaut Aucune erreur signalée
Fonctions repérées par leur seul nom int toto (float arg) { …/* définition */ }; float toto (float arg1, char arg2); … X = toto (2.3, ‘A’); La fonction sera appelée avec le mauvais nombre d’arguments (plantages à cause de mauvaise gestion de la pile) et les mauvais types d’arguments (données incohérentes). Aucune vérification.
Un outil et une pratique Un outil: lint. Voir docs diverses. Analyse statique des codes des sources et warnings divers si incohérence. Une pratique: faire un jeu de fichiers (extension.h par convention) qui seront inclus en tête des fichiers à compiler et forceront les vérifications.
Règles d’exportation - Tout fichier.c qui exporte des objets a un.h de même nom, et l’inclut par #include "toto.h " (si le chemin est absolu ou relatif) ou par #include (si le chemin est conventionnel, défini par une variable système) toto.c toto.h #include " toto.h " extern float fff; float fff = 2.0; int machin (char * s); int machin (char * s) { ……. } - Toute variable exportée (utilisée hors du fichier qui la définit) doit être déclaré « extern » dans le.h et définie dans le.c. - Toute fonction exportée doit être déclarée dans le.h et définie dans le.c
toto.c #include " toto.h " Règles d’importation Tout fichier qui se sert d’objets externes inclut le.h du module qui les définit. client.c toto.h #include " toto.h " Ainsi toute utilisation fautive ou redéclaration d’une variable sera vue par le compilateur. extern float fff; De même pour une utilisation erronée, ou une redéclaration d’une fonction int machin (char * s); char fff; fff=‘A’; machin(2.3);
Bénéfices Le.h déclare un objet Le.c correspondant inclut son propre.h et donc s’oblige à définir les objets déclarés conformément à leur déclaration dans le.h sinon erreur. Les clients incluent le.h et donc s’obligent à utiliser les objets conformément à leur déclaration sinon erreur. L’édition de liens va donc s’occuper de définitions cohérentes avec leur utilisation
Dangers Rien n’est vérifié par le compilateur: c’est une question de discipline! Hélas le compilateur prend des options par défaut quand il tombe sur une fonction non déclarée et la déclare « pour vous ». Le #include fait effectivement et physiquement une inclusion: aucune magie ne fait que le compilateur se souviendrait d’où viennent les portions de textes qu’il compile ensuite. En particulier ne pas oublier le « extern » dans les déclarations de variables: sinon résultats non définis, la variable étant déclarée (avec son adresse et la place mémoire réservée) dans plusieurs modules ensuite reliés par l’édition de liens!
Make Cible: dépendances commande shell La liste de dépendances pour construire la cible avec la commande shell contient en général: les fichiers utilisés directement par la commande et les fichiers.h utilisés toto : toto.c utils.c utils.h gcc toto.c utils.c -o toto Bref la construction d’un Makefile est un problème en soi nécessitant l’inspection des sources. Corrolaire: ne pas cacher les #include au milieu des fichiers.c, les mettre en tête!
Inclusions transitives Un fichier inclus peut lui-même en inclure d’autres. Par exemple une fonction exportée utilise le type FILE: on peut préférer inclure stdio.h dans toto.h (plutôt que dans toto.c avant l’inclusion de toto.h, ce qui crée une contrainte d’utilisation). On peut se retrouver avec des combinaisons compliquées où le même fichier est inclus plusieurs fois. Une technique utilisant le préprocesseur (utilisée dans les fichiers.h standard). #ifndef TOTO_DEJA_INCLU #define TOTO_DEJA_INCLU (ici les déclarations qui ne seront lues qu’une fois même si le fichier est inclus 10 fois) #endif