Question

J'ai travaillé avec un certain nombre de projets C au cours de ma carrière de programmation et les structures de fichiers d'en-tête tombent généralement dans l'une de ces deux motifs:

  1. Un fichier d'en-tête contenant tous les prototypes de fonction
  2. Un fichier de .h pour chaque fichier .c, contenant les prototypes des fonctions définies dans ce module seulement.

Les avantages de l'option 2 sont évidents pour moi - il est moins cher de partager le module entre plusieurs projets et rend les dépendances entre les modules plus faciles à voir

.

Mais quels sont les avantages de l'option 1? Il doit avoir des avantages sinon il ne serait pas si populaire.


Cette question s'appliquerait à C ++, ainsi que C, mais je l'ai jamais vu # 1 dans un projet C ++.

Placement de #defines, etc. structs varie aussi, mais pour cette question, je voudrais me concentrer sur des prototypes de fonction.

Était-ce utile?

La solution

L'option 1 permet d'avoir toutes les définitions dans un seul endroit afin que vous devez inclure / recherche un seul fichier au lieu d'avoir à inclure / recherche de fichiers. Cet avantage est plus évident si votre système est livré en tant que bibliothèque à un tiers -. Ils ne se soucient pas beaucoup sur la structure de votre bibliothèque, ils veulent juste pouvoir l'utiliser

Autres conseils

Je pense que la motivation première de # 1 est ... la paresse. Les gens pensent qu'il est trop difficile de gérer les dépendances que les choses de fractionnement dans des fichiers séparés peuvent rendre plus évidents, et / ou pense qu'il est en quelque sorte « surpuissant » d'avoir pour tout des fichiers séparés.

Il peut aussi, bien sûr, être souvent un cas de « raisons historiques », où le programme ou d'un projet sont passées de quelque chose de petit, et personne ne l'a pris le temps de factoriser les fichiers d'en-tête.

Une autre raison d'utiliser un autre .h pour chaque .c est temps de compilation. S'il n'y a qu'un .h (ou s'il y a plus d'entre eux mais vous les inclure tous dans chaque fichier .c), à chaque fois que vous faites un changement dans le fichier .h, vous devrez recompiler chaque fichier .c. Ceci, dans un grand projet, peut représenter une précieuse quantité de temps se perdre, ce qui peut aussi casser votre flux de travail.

  • 1 est tout simplement inutile. Je ne vois pas une bonne raison de le faire, et beaucoup pour l'éviter.

Trois règles pour suivre # 2 et ont aucun problème:

  • commencer TOUS les fichiers d'en-tête avec un

    #ifndef _HEADER_Namefile
    #define _HEADER_Namefile_
    

fin le fichier avec

    #endif

Cela vous permettra d'inclure le même fichier d'en-tête plusieurs fois sur le même module (peut innadvertely arriver) sans causer de chichi.

  • vous ne pouvez pas avoir des définitions sur vos fichiers d'en-tête ... et que tout le monde est quelque chose pense qu'il / elle le sait, sur les prototypes de fonction, mais ne tient pas compte presque jamais pour les variables globales. Si vous voulez une variable globale, qui par définition devrait être visible à l'extérieur, il est la définition de module C, utilisez le mot-clé extern:

    extern unsigned long G_BEER_COUNTER;
    

qui indique au compilateur que le symbole de G_BEER_COUNTER est en fait un unsigned long (donc, fonctionne comme une déclaration), que sur un autre module aura sa définition correcte / initialisation. (Cela permet également l'éditeur de liens pour garder la table des symboles résolus / non résolue.) La définition réelle (même sans déclaration extern) va dans le fichier .c du module.

  • uniquement sur la nécessité absolue prouvé-vous inclure d'autres têtes dans un fichier d'en-tête. comprennent des énoncés ne devraient être visibles sur les fichiers .c (les modules). Cela vous permet de mieux interpréter les dependecies, et de trouver / à résoudre les problèmes.

Je recommande une approche hybride: faire un en-tête pour chaque composante du programme qui pourrait éventuellement être utilisé indépendamment, puis faire un en-tête de projet qui inclut tous. De cette façon, chaque fichier source n'a besoin que d'inclure un en-tête (pas besoin d'aller mettre à jour tous vos fichiers source si vous refactoring composants), mais vous garder une organisation logique de vos déclarations et de le rendre facile à réutiliser votre code.

Il y a aussi je crois qu'une option 3: chaque .c a son propre .h, mais il y a aussi un .h qui comprend tous les autres fichiers .h. Cela porte le meilleur des deux mondes au détriment de la tenue d'un .h à jour, bien que cela pourrait faire automatiquement.

Avec cette option, vous utiliser en interne les fichiers .h individuels, mais une 3ème partie peut simplement inclure le fichier .h englobante.

Quand vous avez un très grand projet avec des centaines / milliers de petits fichiers d'en-tête, la vérification des dépendances et la compilation peuvent ralentir de manière significative en tant que bon nombre de petits fichiers doivent être ouverts et lus. Ce problème peut être résolu en utilisant souvent les en-têtes précompilés.

En C ++ vous voulez certainement un fichier d'en-tête par classe et utiliser les en-têtes pré-compilés comme mentionné ci-dessus.

Un fichier d'en-tête pour un ensemble du projet est irréalisable à moins que le projet est extrêmement faible - comme un travail scolaire

Cela dépend de la quantité de fonctionnalité est dans un fichier en-tête / source. Si vous devez inclure 10 fichiers juste, disons, sorte quelque chose, il est mauvais.

Par exemple, si je veux utiliser des vecteurs STL I comprennent juste et je me fiche de ce internals sont nécessaires pour vecteur à utiliser. GCC comprend 8 autres en-têtes - allocateur, algobase, construire, non initialisée, vecteur et bvector. Il serait pénible d'inclure tous les 8 juste utiliser vecteur, accepteriez-vous?

têtes internes bibliothèque doivent être aussi rares que possible. Sont plus heureux si Compilateurs ils ne comprennent pas des choses inutiles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top