Pourquoi utiliser des fichiers objects en C?

Lorsque je comstack un programme C, par souci de commodité, j’ai inclus le fichier source pour un certain en-tête à la fin. Donc, si main.c inclut util.h, util.h aura tous les en-têtes que util.c utilisera, décrit les types ou les structures, etc., puis, à la fin, inclura util.c. Ensuite, lorsque je comstack, je n’ai plus qu’à utiliser gcc main.c -o main, et le rest est entièrement traité.

J’ai examiné les normes de codage C, essayant de déterminer quelle est la meilleure façon de faire les choses. Il y en a tellement et beaucoup d’opinions contradictoires que je ne sais pas quoi penser. Pourquoi autant de lieux recommandent-ils de comstackr des fichiers object individuellement au lieu de tous les inclure dans un site Web? util ne touche jamais rien d’autre que util.c, donc les deux sont parfaitement indépendants, et en théorie (ma théorie), tout irait bien, mais je me trompe probablement car il s’agit d’informatique et les gens ont tort même s’ils ont raison, donc si je me trompe déjà, je me trompe probablement.

Certaines personnes disent que les fichiers d’en-tête doivent UNIQUEMENT être des prototypes, et que le fichier source est celui qui l’inclut, et qu’il constitue les en-têtes système nécessaires. D’un sharepoint vue purement esthétique, je préfère de loin avoir toutes les informations (types, en-têtes de système utilisés, prototypes) dans l’en-tête (dans ce cas, util.h) et avoir UNIQUEMENT le code de fonction dans util.c (à l’exception d’un “#include”). util.h “” tout en haut).

Je suppose que le point auquel je veux en venir est que, avec tout ce qui fonctionne, choisir une méthode semble arbitraire pour quelqu’un qui ne comprend pas l’arrière-plan (moi). S’il vous plaît dites-moi pourquoi et quoi.

Bien que votre programme soit petit, cela fonctionnera. Cependant, à un moment donné, votre programme deviendra suffisamment grand pour que la recompilation de tout le programme à chaque fois que vous modifiez une ligne pose un problème.

C’est pourquoi, même plus que d’éviter d’éditer d’énormes fichiers, vous devez séparer votre programme. Si main.c et util.c sont séparément compilés dans des fichiers object, modifier une ligne dans une fonction de main.c ne nécessitera plus de recomstackr tout le code de util.c.

Au moment où votre programme se compose de quelques dizaines de fichiers, cela sera une grande victoire.

Je pense que le fait est que vous voulez inclure uniquement ce qui est nécessaire pour que ce fichier soit indépendant. Cela réduit les temps de compilation globaux en permettant au compilateur de lire uniquement les en-têtes nécessaires plutôt que de lire de manière répétée tous les en-têtes lorsqu’il n’est pas nécessaire de le faire. Par exemple, si votre méthode util.c utilise des fonctions et / ou des types dans mais pas votre util.h , vous souhaiterez inclure uniquement dans util.c sorte que le compilateur comstack util.c il ne comprend alors que , mais si vous incluez dans votre util.h , chaque fichier source incluant util.h inclut également qu’il soit en a besoin ou pas.

Ceci est très négligeable pour les petits projets ne contenant que quelques fichiers, mais une inclusion appropriée des en-têtes peut affecter les temps de compilation des projets plus importants.

En ce qui concerne la question sur les “fichiers object”: lorsque vous comstackz un fichier source dans un fichier object, vous créez un raccourci qui permet au système de construction de recomstackr uniquement les fichiers source contenant des fichiers object obsolètes. C’est un moyen efficace de réduire considérablement les temps de compilation, en particulier pour les grands projets.

Premièrement, inclure un fichier .c à partir d’un fichier .h est complètement bass-ackwards.

La manière “standard” de le faire suit une ligne de pensée à peu près comme ceci:

Vous avez une bibliothèque contenant des dizaines de fonctions. Conserver tout dans un seul gros fichier source signifie que quiconque utilisant votre bibliothèque devra lier toute la bibliothèque, même s’il n’en utilise qu’une seule fonction. (Imaginez lier toute la bibliothèque standard C pour une puts( "Hello" ) .)

Donc, vous divisez les choses en plusieurs fichiers source, qui sont compilés individuellement. Chaque fois que vous apportez des modifications à l’une de vos fonctions, vous devez re-traduire un seul petit fichier source et mettre à jour l’archive de bibliothèque (ou l’exécutable), au lieu de re-traduire le tout dans son intégralité à chaque fois. (Cela rest un problème, car la taille du code a peu à peu évolué avec les améliorations du processeur. Comstackr quelque chose comme la librairie Boost peut encore prendre plusieurs minutes sur du matériel pas trop sophistiqué …)

Maintenant, vous êtes dans une pincée, cependant. La fonction est définie dans le fichier .c et le fichier .o correspondant peut facilement être lié (via une archive .a le cas échéant). Cependant , pour que la fonction (fournie par le fichier .o) soit correctement adressée à partir d’un autre fichier source (“unité de traduction”), votre compilateur doit connaître le nom de la fonction, sa liste de parameters et son type de retour. C’est pourquoi la déclaration de la fonction (c’est-à-dire la fonction head sans son corps) est placée dans un fichier d’en-tête (.h) séparé.

Les autres fichiers sources peuvent maintenant #include le fichier d’en-tête, adresser la fonction correctement (sans que le compilateur sache ce qu’elle fait réellement), et lorsque toutes les parties de votre bibliothèque / programme sont compilées dans des fichiers .o, tout est lié ensemble. .

Le fichier source inclut son propre en-tête, essentiellement pour s’assurer que les deux fichiers s’accordent sur la déclaration de fonction. 😉

C’est à peu près tout, dans la mesure où je peux avoir la peine de l’écrire maintenant. Mettre tout dans un fichier source monolithique est à peine acceptable (en fait, non, ce n’est pas le cas, pas plus de 200 lignes environ), mais inclure le fichier .c à la fin du fichier .h signifie également que vous avez appris votre codage C en regardant un code affreux au lieu d’un bon livre, ou une personne qui vous guidera, vous ne devriez jamais enseigner à quelqu’un de codé en C dans sa vie. Aucune infraction prévue. 😉

PS: Les fichiers d’en-tête fournissent également un bon résumé / contrôle d’un morceau de code. Les langages qui ne fournissent pas d’en-têtes – Java, par exemple – ont besoin d’IDE ou d’outils de documentation pour extraire ce type d’informations. Personnellement, j’ai trouvé que les fichiers d’en-tête constituaient un avantage et non un passif.

Veuillez utiliser les fichiers *.h et *.c manière habituelle: les fichiers *.h sont #include d in *.c ; *.h contient uniquement les définitions de macros, les déclarations de type de données, les déclarations de fonction et les déclarations de données extern . Toutes les définitions sont dans les fichiers *.c . C’est ainsi que tout le monde organise les programmes C, fait une faveur à vos semblables (qui pourraient un jour comprendre votre programme). Si quelque chose dans file.c est utilisé à l’extérieur, vous écrivez file.h contenant les déclarations de ce que ce fichier doit être utilisé à l’extérieur, et incluez-le dans file.c (pour vérifier que les déclarations et les définitions concordent) et en utilisant des fichiers *.c . Si un groupe de *.h est toujours inclus ensemble, cela peut signifier que la scission en *.c n’est pas correcte (ou du moins celle du *.h ; vous devriez peut-être en faire un .h avec toutes ces déclarations, et en créant *.h pour un usage interne, le cas échéant, parmi le groupe de fichiers *.c associés).

[Si un programme que vous décrivez décrit mon chemin, je peux vous assurer que je l’éviterai comme la peste. L’obscurcissement supplémentaire pourrait être une bonne chose à l’ IOCCC , mais pas par moi. C’est un signe certain de quelqu’un qui ne sait pas comment organiser un programme proprement, alors le programme ne vaut probablement pas la peine d’être essayé.]

Re: Compilation séparée: Vous divisez un programme C pour faciliter la compréhension des éléments. Vous pouvez masquer les détails du fonctionnement des fichiers C (pensez static ), ce qui permet de prendre en charge la modularité de Parnas. Cela signifie également que si vous modifiez un fichier, vous n’avez pas à tout recomstackr.

Re: Différentes normes de programmation en C: Oui, il y en a beaucoup autour. Choisissez-en un avec lequel vous vous sentez à l’aise et respectez-le. Si vous travaillez sur un projet, respectez leurs normes.

L’approche “inclure dans une seule unité de traduction” devient très inefficace pour tout projet de taille importante, elle n’est pas pratique pour les projets répartis entre plusieurs développeurs.

De plus, lors de la création de bibliothèques statiques, si tout dans la bibliothèque provenait d’une seule unité de traduction, tout code qui y serait lié obtiendrait tout le code de la bibliothèque, qu’il soit référencé ou non.

Un projet utilisant un gestionnaire de génération tel que make ou les fonctionnalités disponibles dans la plupart des IDE utilise des dépendances de fichiers d’en-tête pour permettre une construction incrémentielle . comstackr uniquement les sources modifiées ou dépendantes de fichiers modifiés. Les dépendances étant déterminées par les inclusions de fichier, la réduction des dépendances redondantes accélère le temps de génération.

Un projet commercial typique peut comprendre des centaines de milliers de lignes de code et quelques centaines de fichiers sources. les temps de reconstruction complets peuvent varier de quelques minutes à quelques heures. Si, dans votre cycle de développement, vous devez attendre si longtemps entre les changements de code et les tests, la productivité sera très faible!