150 votes

Inclure un fichier source C dans un autre ?

Est-il acceptable (ou même recommandé/bonne pratique) de #include a .c dans un autre .c fichier ?

143voto

Utilisée correctement, cette technique peut s'avérer utile.

Supposons que vous ayez un sous-système complexe, dont les performances sont critiques, avec une interface publique relativement 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 un grand nombre de données privées. Si vous travaillez avec des systèmes embarqués non triviaux, vous êtes probablement confronté à 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 pour tout ce qui est déclaré extern.

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

  • Amélioration de la performance et de la taille du code - les appels de fonction seront inlined dans de nombreux cas. Même sans inlining, le compilateur a la possibilité de produire un code plus efficace.

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

  • Éviter la pollution des espaces de noms et son corollaire - vous pouvez utiliser des noms moins lourds.

  • Compilation et liaison plus rapides.

Mais vous obtenez également un désordre infernal lorsqu'il s'agit de modifier ce fichier et vous perdez la modularité implicite. Cela peut être surmonté en divisant le source en plusieurs fichiers et en les incluant pour produire une seule unité de compilation.

Il faut cependant imposer certaines conventions pour gérer cela correctement. Celles-ci dépendront dans une certaine mesure de votre chaîne d'outils, mais quelques indications générales sont -

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

  • Ayez un fichier .c principal qui inclut tous les fichiers .c subsidiaires. Il peut également inclure le code de l'interface publique.

  • Utilisez les gardes du compilateur pour vous assurer que les en-têtes et les modules sources privés 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.

  • Maintenir la distinction conceptuelle entre les fichiers .c et .h. Cela permet de tirer 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 quelques segments vides lors de l'édition de liens). L'énorme avantage est que les autres outils (par exemple, les IDE) traiteront ces fichiers de manière appropriée.

78voto

Steven A. Lowe Points 40596

C'est ok ? oui, ça compile

Est-ce recommandé ? non - Les fichiers .c sont compilés en fichiers .obj, qui sont liés ensemble 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. Il n'est donc pas nécessaire d'inclure un fichier .c dans un autre. Ce que vous voulez probablement faire à la place, c'est de créer un fichier .h qui liste les fonctions/variables disponibles dans l'autre fichier .c, et d'inclure le fichier .h.

17voto

Andrew Edgecombe Points 13183

Non.

En fonction de votre environnement de construction (que vous ne précisez pas), vous trouverez peut-être que cela fonctionne exactement comme vous le souhaitez.

Cependant, il y a beaucoup d'environnements (à la fois des IDE et beaucoup de Makefiles faits à la main) qui s'attendent à compiler *.c - si cela se produit, vous vous retrouverez probablement avec des erreurs de linker dues à des symboles dupliqués.

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

Si vous devez absolument #inclure la source (ce qui est généralement à éviter), utilisez un suffixe de fichier différent pour le fichier.

10voto

Matthew Alford Points 31

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 par un système de messages. Ces gestionnaires de messages sont publics et appellent de nombreuses fonctions statiques locales pour faire leur travail. Le problème est apparu lorsque nous avons essayé d'obtenir une couverture pour nos cas de tests unitaires, car la seule façon d'exercer ce code d'implémentation privé était indirectement par l'interface de message publique. Avec certaines fonctions de travailleur enfoncées jusqu'au genou dans la pile, cela s'est avéré être un cauchemar pour obtenir une couverture appropriée.

L'inclusion des fichiers .c nous a permis d'atteindre le rouage de la machine que nous voulions tester.

10voto

sumitroy Points 119

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 fichiers 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 dans main.c une fonction qui est déclarée dans le fichier support.c, vous devez la déclarer dans main également en utilisant la classe extern storage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X