Est-il acceptable (ou même recommandé/bonne pratique) de #include
.c dans un autre fichier .c? Que se passe-t-il lorsqu'ils sont inclus dans un fichier de projet?
Utilisé correctement, cela peut être une technique utile.
Supposons que vous disposiez d'un sous-système complexe et critique en termes de performances, doté d'une interface publique relativement petite et de nombreux codes de mise en œuvre non réutilisables. Le code comporte 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 intégrés non triviaux, vous faites probablement face à cette situation assez souvent.
Votre solution sera probablement en couches, 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 offrent une optimisation décente pour une seule unité de compilation, mais sont très pessimistes quant à tout ce qui est déclaré externe.
Si vous mettez tout dans un module source C, vous obtenez -
Amélioration des performances et de la taille du code - les appels de fonction seront en ligne dans de nombreux cas. Même sans alignement, le compilateur a la possibilité de produire un code plus efficace.
Lien au niveau des données et des fonctions cachées.
Éviter la pollution des espaces de noms et son corollaire - vous pouvez utiliser des noms moins compliqués.
Compilation et liaison plus rapides.
Mais vous obtenez également un désordre impie lors de la modification de ce fichier et vous perdez la modularité implicite. Cela peut être surmonté en scindant la source en plusieurs fichiers et en les incluant pour produire une seule unité de compilation.
Vous devez toutefois imposer certaines conventions pour gérer cela correctement. Cela dépendra dans une certaine mesure de votre chaîne d’outils, mais quelques indications générales sont -
Placez l'interface publique dans un fichier d'en-tête séparé - vous devriez le faire de toute façon.
Ayez un fichier principal .c qui inclut tous les fichiers auxiliaires .c. Cela pourrait également inclure le code de l'interface publique.
Utilisez les gardes du compilateur pour vous assurer que les en-têtes privés et les modules source ne sont pas inclus par des 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. Ceci exploite les 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 include, 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 (tels que les IDE) traiteront ces fichiers de manière appropriée.
est-ce que c'est bon? oui, ça va compiler
est-ce recommandé? no - Les fichiers .c sont compilés en fichiers .obj, qui sont liés entre eux après la 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. Au lieu de cela, vous voudrez probablement créer un fichier .h qui répertorie les fonctions/variables disponibles dans l’autre fichier .c et inclure le fichier .h.
Non.
En fonction de votre environnement de construction (vous ne spécifiez pas), vous constaterez qu'il fonctionne exactement comme vous le souhaitez.
Cependant, de nombreux environnements (à la fois les IDE et de nombreux Makefiles conçus à la main) s'attendent à compiler * .c. Si cela se produit, vous obtiendrez probablement des erreurs de l'éditeur de liens dues à des symboles en double.
En règle générale, cette pratique devrait ê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.
Je pensais partager une situation dans laquelle mon équipe avait décidé d'inclure des fichiers .c. Notre archicture se compose en grande partie de modules 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 lorsque nous avons cherché à obtenir une couverture pour nos cas de test unitaires, car le seul moyen d’exercer ce code de mise en œuvre privé était indirectement via l’interface de message publique. Avec certaines fonctions de travailleur aux genoux dans la pile, cela s'est révélé être un cauchemar pour obtenir une couverture adéquate.
L’inclusion des fichiers .c nous a permis d’atteindre le rouage de la machine que nous voulions tester.
L'extension du fichier n'a pas d'importance pour la plupart des compilateurs C, donc cela fonctionnera.
Cependant, en fonction de vos paramètres de fichier ou de projet, le fichier c inclus peut générer un fichier objet séparé. Lors de la liaison, cela pourrait conduire à des symboles à double définition.
Vous pouvez utiliser le compilateur gcc sous Linux pour lier deux fichiers c en une sortie. Supposons que vous avez deux fichiers c, l'un est 'main.c' et l'autre, 'support.c'. Donc, la commande pour relier ces deux est
gcc main.c support.c -o main.out
Ainsi, 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 en utilisant également la classe de stockage extern.
Vous pouvez inclure correctement les fichiers .C ou .CPP dans d’autres fichiers sources. En fonction de votre IDE, vous pouvez généralement empêcher les doubles liaisons en examinant 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 sélectionnant Propriétés, puis en décochant/vérifiant la compilation/lier/exclure de la construction, ou autre option. peut être. Ou vous ne pourriez pas inclure le fichier dans le projet lui-même, ainsi IDE ne saura même pas qu'il existe et n'essaiera pas de le compiler. Et avec les makefiles, vous ne voudriez tout simplement pas y placer le fichier pour compiler et relier.
EDIT: Désolé je l'ai fait une réponse au lieu d'une réponse sur d'autres réponses :(
Le langage C n'interdit pas ce genre de #include, mais l'unité de traduction résultante doit toujours être un C valide.
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 pour qu'elle soit compilée sans celui qui ne peut pas être compilé indépendamment.
Inclure le fichier C dans un autre fichier est légal, mais déconseillé, à moins que vous ne sachiez exactement pourquoi vous faites cela et que tentez-vous de réaliser.
Je suis presque sûr que si vous publiez ici la raison pour laquelle votre communauté se trouve derrière votre question, elle vous trouvera un autre moyen plus approprié d’atteindre votre objectif (notez le "presque", car il est possible que ce soit le cas. la solution compte tenu du contexte).
À propos, 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 dans le projet, vous rencontrerez probablement un problème de symbole en double, mais la même fonction sera définie deux fois (sauf si elles sont toutes statiques).