Y compris un fichier source C dans un autre?


Réponses:


113

Utilisé correctement, cela peut être une technique utile.

Supposons que vous ayez un sous-système complexe et critique pour les performances avec une interface publique assez petite et beaucoup de code d'implémentation non réutilisable. Le code compte plusieurs milliers de lignes, une centaine de fonctions privées et pas mal de données privées. Si vous travaillez avec des systèmes embarqués non triviaux, vous gérez probablement cette situation assez fréquemment.

Votre solution sera probablement stratifiée, modulaire et découplée et ces aspects peuvent être utilement représentés et renforcés en codant différentes parties du sous-système dans différents fichiers.

Avec C, vous pouvez perdre beaucoup en faisant cela. Presque toutes les chaînes d'outils fournissent une optimisation décente pour une seule unité de compilation, mais sont très pessimistes sur tout ce qui est déclaré extern.

Si vous mettez tout dans un seul module source C, vous obtenez -

  • Améliorations des performances et de la taille du code - les appels de fonction seront intégrés dans de nombreux cas. Même sans insertion, le compilateur a la possibilité de produire du code plus efficace.

  • Masquage des données et des fonctions au niveau des liens.

  • Évitement de la pollution des espaces de noms et de son corollaire - vous pouvez utiliser des noms moins compliqués.

  • Compilation et liaison plus rapides.

Mais vous obtenez également un désordre impie en ce qui concerne l'édition de ce fichier et vous perdez la modularité implicite. Cela peut être surmonté en divisant la source en plusieurs fichiers et en les incluant pour produire une seule unité de compilation.

Vous devez cependant imposer certaines conventions pour gérer cela correctement. Celles-ci dépendront dans une certaine mesure de votre chaîne d'outils, mais certains indicateurs généraux sont -

  • Mettez l'interface publique dans un fichier d'en-tête séparé - vous devriez le faire de toute façon.

  • Avoir un fichier .c principal qui inclut tous les fichiers .c subsidiaires. Cela pourrait également inclure le code de l'interface publique.

  • Utilisez les protections du compilateur pour vous assurer que les en-têtes privés et les modules sources ne sont pas inclus par les unités de compilation externes.

  • Toutes les données et fonctions privées doivent être déclarées statiques.

  • Conservez la distinction conceptuelle entre les fichiers .c et .h. Cela tire parti des conventions existantes. La différence est que vous aurez beaucoup de déclarations statiques dans vos en-têtes.

  • Si votre chaîne d'outils n'impose aucune raison de ne pas le faire, nommez les fichiers d'implémentation privés comme .c et .h. Si vous utilisez des gardes d'inclusion, ceux-ci ne produiront aucun code et n'introduiront aucun nouveau nom (vous pouvez vous retrouver avec des segments vides lors de la liaison). L'énorme avantage est que d'autres outils (par exemple les IDE) traiteront ces fichiers de manière appropriée.


1
+1 c'est toujours la réalité, alors que de meilleurs compilateurs rendront cette méthode obsolète avec le temps. GCC 4.5 avec l'optimisation du temps de liaison est un grand pas en avant.
u0b34a0f6ae

J'ai vu tellement de programmes faire cela, et cela m'énerve quand j'essaye de réutiliser leur code. Merci d'avoir expliqué pourquoi ils le font et d'avoir suggéré l'utilisation d'un garde (ce qui n'est souvent pas fait).
Joey Adams

Dans le développement embarqué pour C51, l'utilisation de fichiers C externes et multiples n'a causé que des maux de tête. Je passe à un fichier C incluant tous les autres pour récupérer mon temps.
mahesh

Pour les enregistrements: GCC prend en charge l'optimisation dans différentes unités de traduction, voir ce fil SO et la section du manuel GCC sur l' optimisation du temps de liaison .
Twonky

60

Est-ce que c'est bon? oui, il compilera

est-ce recommandé? no - les fichiers .c se compilent en fichiers .obj, qui sont liés après compilation (par l'éditeur de liens) dans l'exécutable (ou la bibliothèque), il n'est donc pas nécessaire d'inclure un fichier .c dans un autre. Ce que vous voudrez probablement faire à la place est de créer un fichier .h qui répertorie les fonctions / variables disponibles dans l'autre fichier .c, et d'inclure le fichier .h


14
Il convient également de noter que même s'il compile, il peut ne pas être lié si le fichier #included .c est également compilé et que les deux fichiers objets sont liés ensemble - vous pourriez vous retrouver avec des symboles définis de manière multiple.
Nick Meyer

1
Une petite question. J'ai un fichier d'en-tête déclarant une méthode struct + et également le fichier .c correspondant pour les définir. Si cette méthode prend la structure comme paramètre, comment éviter d'inclure le fichier .c dans un autre fichier .c où la méthode principale est définie?
stdout

12

Non.

En fonction de votre environnement de construction (que vous ne spécifiez pas), vous constaterez peut-être qu'il fonctionne exactement comme vous le souhaitez.

Cependant, il existe de nombreux environnements (à la fois des IDE et de nombreux Makefiles fabriqués à la main) qui s'attendent à compiler * .c - si cela se produit, vous vous retrouverez probablement avec des erreurs de l'éditeur de liens dues à des symboles en double.

En règle générale, cette pratique doit être évitée.

Si vous devez absolument #inclure la source (et généralement cela doit être évité), utilisez un suffixe de fichier différent pour le fichier.


9

J'ai pensé partager une situation où mon équipe a décidé d'inclure des fichiers .c. Notre architecture se compose en grande partie de modules qui sont découplés via un système de messagerie. Ces gestionnaires de messages sont publics et appellent de nombreuses fonctions de travail statiques locales pour effectuer leur travail. Le problème est survenu en essayant d'obtenir une couverture pour nos cas de test unitaires, car le seul moyen d'exercer ce code d'implémentation privé était indirectement via l'interface de message public. Avec certaines fonctions des travailleurs jusqu'aux genoux dans la pile, cela s'est avéré être un cauchemar pour obtenir une couverture adéquate.

L'inclusion des fichiers .c nous a donné un moyen d'atteindre le rouage de la machine que nous étions intéressants à tester.


6

Vous pouvez utiliser le compilateur gcc sous Linux pour lier deux fichiers c en une seule sortie. Supposons que vous ayez deux fichiers c, l'un est «main.c» et l'autre «support.c». Donc, la commande pour lier ces deux est

gcc main.c support.c -o main.out

Par ces deux fichiers seront liés à une seule sortie main.out Pour exécuter la sortie, la commande sera

./main.out

Si vous utilisez la fonction dans main.c qui est déclarée dans le fichier support.c, vous devez la déclarer dans main également en utilisant la classe de stockage externe.


5

L'extension du fichier n'a pas d'importance pour la plupart des compilateurs C, donc cela fonctionnera.

Cependant, selon vos paramètres de makefile ou de projet, le fichier c inclus peut générer un fichier objet distinct. Lors de la liaison, cela peut conduire à des symboles doubles définis.


3

Vous pouvez correctement inclure des fichiers .C ou .CPP dans d'autres fichiers source. En fonction de votre IDE, vous pouvez généralement empêcher le double lien en regardant les propriétés des fichiers source que vous souhaitez inclure, généralement en cliquant dessus avec le bouton droit de la souris et en cliquant sur Propriétés, et décochez / cochez compiler / lier / exclure de la construction ou toute autre option. peut être. Ou vous ne pouvez pas inclure le fichier dans le projet lui-même, ainsi l'EDI ne saura même pas qu'il existe et n'essaiera pas de le compiler. Et avec makefiles, vous ne mettriez tout simplement pas le fichier dedans pour la compilation et la liaison.

EDIT: Désolé, je lui ai fait une réponse au lieu d'une réponse sur d'autres réponses :(


1

Le langage C n'interdit pas ce type de #include, mais l'unité de traduction résultante doit toujours être valide C.

Je ne sais pas quel programme vous utilisez avec un fichier .prj. Si vous utilisez quelque chose comme "make" ou Visual Studio ou autre, assurez-vous simplement de définir sa liste de fichiers à compiler sans celui qui ne peut pas être compilé indépendamment.


0

L'inclusion d'un fichier C dans un autre fichier est légale, mais ce n'est pas une chose à faire, à moins que vous ne sachiez exactement pourquoi vous faites cela et ce que vous essayez de réaliser.
Je suis presque sûr que si vous postez ici la raison pour laquelle, derrière votre question, la communauté vous trouvera un autre moyen plus approprié pour atteindre votre objectif (veuillez noter le «presque», car il est possible que ce soit la solution compte tenu du contexte ).

Au fait, j'ai raté la deuxième partie de la question. Si le fichier C est inclus dans un autre fichier et dans le même temps inclus dans le projet, vous vous retrouverez probablement avec un problème de symbole en double pourquoi lier les objets, c'est-à-dire que la même fonction sera définie deux fois (à moins qu'ils ne soient tous statiques).


-6

vous devriez ajouter un en-tête comme celui-ci

#include <another.c>

Remarque: les deux fichiers doivent être placés au même endroit

J'utilise ceci dans codevison AVR pour les micro-contrôleurs ATMEGA et je fonctionne vraiment mais cela ne fonctionne pas dans un fichier de langage C normal

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.