Comment un compilateur C / C ++ trouve-t-il les définitions de prototypes dans les fichiers d’en-tête?

Quand je déclare une fonction dans un fichier d’en-tête et que je mets la définition de cette fonction dans un autre fichier, comment le compilateur / éditeur de liens trouve-t-il la définition? Recherche-t-il systématiquement chaque fichier de son chemin ou existe-t-il une solution plus élégante? Cela me dérange depuis quelques jours et je suis incapable de trouver une explication à cela.

Le compilateur ne fait pas cela, l’éditeur de liens fait.

Alors que le compilateur fonctionne sur un fichier source à la fois, lorsque l’éditeur de liens est appelé, il reçoit le nom de tous les fichiers object générés par le compilateur, ainsi que toutes les bibliothèques dans lesquelles l’utilisateur souhaite être lié. L’éditeur de liens a une connaissance complète de l’ensemble des fichiers susceptibles de contenir la définition. Il suffit de regarder dans les tables de symboles de ces fichiers objects. Il n’est pas nécessaire de faire des recherches au-delà de cela.

Par exemple, supposons que foo.h et foo.c définissent et implémentent function foo() , et bar.h et bar.c définissent et implémentent bar() . Dites bar appelle foo pour que bar.c inclue foo.h. Cette compilation comporte trois étapes:

 gcc -c foo.c gcc -c bar.c gcc foo.o bar.o -o program 

La première ligne comstack foo.c, produisant foo.o. La seconde comstack bar.c, produisant bar.o. À ce stade, dans le fichier object bar.o, foo est un symbole externe. La troisième ligne appelle l’éditeur de liens, qui relie ensemble foo.o et bar.o en un exécutable appelé “programme”. Lorsque l’éditeur de liens traite bar.o, il voit le symbole externe non résolu foo . Il recherche donc dans la table des symboles de tous les autres fichiers object liés (dans ce cas, juste foo.o) et trouve foo dans foo.o. complète le lien.

Avec les bibliothèques, cela est un peu plus compliqué, et l’ordre dans lequel elles apparaissent sur la ligne de commande peut avoir de l’importance en fonction de votre éditeur de liens, mais c’est généralement le même principe.

Lorsque vous comstackz un fichier .cpp, le compilateur génère deux tables dans le fichier .obj: une liste de symboles qu’il prévoit de définir en externe , ainsi qu’une liste de symboles définis dans ce module particulier.

L’éditeur de liens prend tous les fichiers .obj qui ont été générés par le compilateur, puis (comme son nom l’indique) les lie tous ensemble. Ainsi, pour chaque module, il examine la liste des symboles marqués “définie en externe” et examine tous les autres modules qui lui ont été atsortingbués.

Ainsi, il ne fait que “rechercher” dans les modules que vous avez indiqué chercher dans.

S’il ne trouve pas le symbole dans l’un des autres modules, c’est alors que vous obtenez l’erreur “référence non définie”.

Supposons que vous avez un fichier foo.cpp avec un #include foo.h et peut-être d’autres inclus. Les en-têtes peuvent bien sûr avoir leur propre # include-s.

Le préprocesseur commencera par le fichier foo.cpp, parsingra le #includes et lira le contenu de l’en-tête. Le résultat sera le texte des fichiers d’en-tête et foo.cpp “aplati”. Le compilateur travaillera alors à partir de ce texte. Si une variable / fonction / etc aurait dû être déclarée quelque part dans un en-tête introuvable, le compilateur signalera une erreur.

Le point fondamental est que le compilateur doit voir toutes ses déclarations à la suite des fichiers .cpp et des en-têtes.