Que devrait contenir le fichier C et que devrait contenir le fichier H ? En ligne Inclure un fichier source C dans un autre ? Fichier source c

Un collègue qui commençait à programmer en C m'a récemment posé une question similaire. Et j’ai pensé que c’était une bonne occasion de partager ma compréhension de cette question. Parce que même les programmeurs expérimentés n’ont pas toujours des points de vue similaires sur cette question.

C'est en partie une question de goût, donc si quelqu'un est intéressé par la façon dont je le fais, bienvenue chez le chat.

Malgré le fait que « toute la vérité » sur les fichiers h soit contenue dans la section correspondante de la description du préprocesseur gcc, je me permettrai quelques explications et illustrations.

Ainsi, littéralement, un fichier d'en-tête (fichier h) est un fichier contenant des déclarations C et des définitions de macros destinées à être utilisées dans plusieurs fichiers sources (fichiers c). Illustrons cela.

Il est facile de remarquer que les fonctions 1 et 2, ainsi que la macro 2, sont mentionnées dans les deux fichiers. Et comme l'inclusion des fichiers d'en-tête produit les mêmes résultats que la copie du contenu dans chaque fichier C, nous pouvons procéder comme suit :

Ainsi, nous avons simplement extrait la partie commune des deux fichiers et l'avons placée dans le fichier d'en-tête.
Mais le fichier d’en-tête est-il une interface dans ce cas ?

  • Si nous devons utiliser la fonctionnalité que les fonctions 1 et 2 implémentent ailleurs, alors Oui
  • Si la macro 2 est destinée uniquement à être utilisée dans les fichiers Unit1.c et Unit2.c, alors elle n'a pas sa place dans le fichier d'interface
De plus, a-t-on vraiment besoin de deux fichiers C pour implémenter l'interface définie dans le fichier d'en-tête ? Ou est-ce qu'un seul suffit ?
La réponse à cette question dépend des détails d'implémentation des fonctions d'interface et de l'endroit où elles sont implémentées. Par exemple, si vous rendez les diagrammes plus détaillés, vous pouvez imaginer un scénario dans lequel les fonctions d'interface sont implémentées dans différents fichiers :


Cette option de mise en œuvre conduit à une cohérence élevée du code, une faible testabilité et une difficulté à réutiliser de tels modules.
Afin d'éviter de telles difficultés, je considère toujours le fichier C et le fichier d'en-tête comme un seul module. Dans lequel,
  • Le fichier d'en-tête contient uniquement les déclarations de fonctions, types et macros qui font partie de l'interface de ce module.
  • Le fichier C, à son tour, doit contenir l'implémentation de toutes les fonctions déclarées dans le fichier h, ainsi que les types privés, les macros et les fonctions nécessaires à l'implémentation de l'interface.
Ainsi, si je devais implémenter le code qui correspond au schéma ci-dessus, j'essaierais d'obtenir ce qui suit (les terminaisons _с et _h dans les noms de fichiers ont été ajoutées en raison de l'impossibilité d'utiliser un point dans l'outil que j'ai utilisé pour créer les schémas) :


Le schéma montre qu'il s'agit en fait de deux modules indépendants, chacun possédant sa propre interface sous la forme d'un fichier d'en-tête. Cela permet d'utiliser uniquement l'interface réellement nécessaire dans ce cas particulier. De plus, ces modules peuvent être testés indépendamment les uns des autres.
Le lecteur a probablement remarqué que la macro 2 du fichier d'en-tête était à nouveau renvoyée sous forme de copie dans les deux fichiers C. Bien sûr, ce n’est pas très pratique à entretenir. Mais intégrer cette macro à l’interface n’est pas correct.
Dans de tels cas, je préfère créer un fichier d'en-tête séparé contenant les types et macros nécessaires à plusieurs fichiers C.

J'espère avoir pu identifier les entités qui doivent être placées dans les fichiers d'en-tête. Et aussi, montrez la différence entre les interfaces et les fichiers contenant les déclarations et les macros requises par plusieurs fichiers C.

Merci de votre attention au matériel.

Fichiers source

Le texte d'un programme C peut être divisé en plusieurs fichiers sources. Le fichier source est fichier texte, qui contient soit l'intégralité du programme, soit une partie de celui-ci. Lorsqu'un programme source est compilé, chacun de ses fichiers source constitutifs doit être compilé séparément puis lié aux autres fichiers par l'éditeur de liens. Les fichiers sources individuels peuvent être combinés en un seul fichier source, compilé comme une seule unité, à l'aide d'une directive de préprocesseur. #inclure.

Le fichier source peut contenir n'importe quelle combinaison holistique de directives, d'instructions du compilateur, de déclarations et de définitions. L'intégrité signifie que les objets tels que les définitions de fonctions, les structures de données ou un ensemble de directives de compilation conditionnelle associées doivent résider entièrement dans un fichier, c'est-à-dire qu'ils ne peuvent pas commencer dans un fichier et continuer dans un autre.

Le fichier source n'a pas besoin de contenir des instructions exécutables. Parfois, il est pratique de placer les définitions de variables dans un fichier et d'utiliser ces variables dans d'autres fichiers en les déclarant. Dans ce cas, les définitions de variables deviennent facilement consultables et modifiables. Pour les mêmes raisons, les constantes nommées et les définitions de macros sont généralement collectées dans des fichiers séparés et incluses via une directive du préprocesseur. #inclure dans les fichiers sources qui les nécessitent.

Les instructions adressées au compilateur ne s'appliquent généralement qu'à des sections spécifiques du fichier source. Les actions spécifiques du compilateur spécifiées par les instructions sont déterminées par l'implémentation spécifique du compilateur C.

Dans l'exemple suivant, le programme source se compose de deux fichiers sources. Les fonctions principal Et maximum Présenté dans fichiers séparés. Fonction principal utilise la fonction maximum en cours de sa mise en œuvre.

/* fichier source 1 - fonction principale */

externe int max(int, int); /* déclaration de fonction */

main() /* définition de la fonction */

int w = UN, x = DEUX, y = TROIS ;

/* fichier source 2 - fonction max */

int max (a, b) /* définition de la fonction */

Dans le premier fichier source, la fonction maximum déclaré mais non défini. Cette déclaration de fonction est appelée pré-déclaration ; il permet au compilateur de contrôler les appels à une fonction avant qu'elle ne soit définie. Définition de la fonction principal contient des appels de fonction maximum.

Les lignes commençant par le symbole # sont des directives du préprocesseur. Les directives indiquent au préprocesseur la nécessité de remplacer les identifiants UN, DEUX, TROIS par les valeurs correspondantes dans le premier fichier source. La portée des directives ne s'étend pas au deuxième fichier source.

support.microsoft

Lorsque vous modifiez des fichiers source dans Visual C++ et que vous les enregistrez, les lignes doivent se terminer par la combinaison « CR/LF » [retour chariot, saut de ligne]. DANS Systèmes UNIX les lignes se terminent par "LF". Ainsi, lors de la visualisation de fichiers modifiés dans Groupe Windows Sur les systèmes UNIX, de nombreux caractères « ^M » peuvent apparaître sur les lignes. Cela ne se produit que lorsque vous utilisez un éditeur qui ne sait pas interpréter Fichier Windows. Visual C++ peut ouvrir des fichiers dont les lignes se terminent par la création UNIX LF. Si vous modifiez ce fichier et l'enregistrez depuis Visual C++, alors il est enregistré au format Windows (vous verrez CR/LF et non le LF qui était auparavant sur le système).

Cet article décrit les procédures d'enregistrement d'un fichier modifié créé sur la plateforme Windows dans un format pouvant être utilisé sur les systèmes UNIX.

NOTE: Visual C++.NET IDE contient des fonctions disponibles pour enregistrer un fichier au format UNIX. Dans l'EDI, enregistrez le fichier en utilisant Enregistrer sous..., sélectionnez Enregistrer dans la liste déroulante Enregistrer avec encodage..., et appuyez sur le bouton thrn Oui. Sélectionnez Encodage de chaîne dans la liste déroulante UNIX (LF) puis cliquez sur le bouton D'ACCORD.

Vous pouvez utiliser les étapes suivantes pour créer un projet d'application console Win32 qui convertit un fichier contenant « CR/LF » pour terminer la ligne « LF » :

  1. Pour en créer un nouveau à l'aide des applications console Win32, un projet vide nommé DOS2UNIX.
  2. Depuis Déposer menu, appuyez sur le bouton Nouveau puis cliquez sur le bouton Des dossiers Languette.
  3. Sélectionner Fichier source C/C++ et entrez le nom du nouveau fichier DOS2UNIX.cpp.
  4. Collez le code suivant dans DOS2UNIX.cpp :

    #inclure #inclure #inclure en utilisant l'espace de noms std ; int main(int argc, char* argv) ( if(argc !=2) ( cout<< "Please specify: dos2unix filename" << endl; return 0; } char ch; char temp="\0"; //Open the file for reading in binarymode. ifstream fp_read(argv, ios_base::in \ / ios_base::binary); sprintf(temp, "%s.temp", argv); //Create a temporary file for writing in the binary mode. This //file will be created in the same directory as the input file. ofstream fp_write(temp, ios_base::out \ / ios_base::trunc \ / ios_base::binary); while(fp_read.eof() != true) { fp_read.get(ch); //Check for CR (carriage return) if((int)ch == 0x0D) continue; if (!fp_read.eof())fp_write.put(ch); } fp_read.close(); fp_write.close(); //Delete the existing input file. remove(argv); //Rename the temporary file to the input file. rename(temp, argv); //Delete the temporary file. remove(temp); return 0; }

  5. Depuis Construction menu, appuyez sur le bouton Création de DOS2UNIX.exe pour créer un fichier EXE.

Vous devrez peut-être tester ce fichier exe pour voir s'il fonctionne correctement. Pour ce faire, ouvrez le fichier dans l'éditeur binaire Visual C++ lorsque vous sélectionnez. Ouvrir en groupe Déposer menu en sélectionnant DOS2UNIX.ex, Paramètres Ouvrir commeÀ qui Binaire puis en cliquant Ouvrir. Par exemple, si le fichier contient « hellocrlfworld », les données du fichier binaire (hexadécimal) ressembleraient à ceci :

48 65 6 C 6 C 6F 0 D 0A 57 6F 72 6 C 64

Cela équivaut à :

Bonjour
Monde

À l'invite de commande, exécutez dos2unix.exe . Ensuite, ouvrez le fichier dans l'éditeur binaire Visual C++. Vous verrez que les 0x0d sont supprimés. Jusqu'à ce que vous modifiiez le fichier et que vous l'enregistriez dans Visual C++, 0x0d n'apparaîtra pas.

Cela peut être utilisé en combinaison avec le modèle d'automatisation Visual C++ pour automatiser l'ensemble du processus. Un simple script de macro Microsoft Visual Basic peut être écrit pour appeler cet outil, mais l'outil doit d'abord être ajouté Service le menu ressemble à ceci :

  1. Depuis Service menu, appuyez sur le bouton Paramètres puis cliquez sur le bouton Service Languette.
  2. Fournissez un nom tel que DOS2UNIX et indiquez le chemin complet du fichier Dos2unix.exe dans Équipe champ d'édition.
  3. Définissez l'argument sur $(Filename)$(FileExt).
  4. Spécifiez le répertoire source $(WkspDir) (spécifiez votre propre chemin).

Pour vérifier le fonctionnement du programme, ouvrez le fichier dans l'éditeur Visual C++, puis depuis Service le menu Démarrer DOS2UNIX moyens. Vous verrez que le fichier ouvert dans l'éditeur a vu tous ses caractères CR supprimés.

Si vous souhaitez automatiser ce processus, gérez-le de manière à ce que chaque fois que vous enregistrez un fichier ouvert dans l'éditeur Visual C++, DOS2UNIX.exe soit appelé pour supprimer les 0x0d, puis utilisez la macro VBScript suivante :

"Cet événement est déclenché chaque fois que le document est enregistré dans l'éditeur VC++. Sub Application_DocumentSave(theDocument) "Cela appellera l'outil utilisateur dans le menu Outils. "Modifiez le numéro en fonction de ce que vous avez. Par défaut, vous n'avez que 6 outils dans le menu Outils, donc l'outil DOS2UNIX sera le 7ème. ExecuteCommand "UserTool7" Fin du sous-marin

Ce code VBScript ne fonctionnera que si des fichiers sont ouverts dans l'éditeur Visual C++. C'est le seul moyen d'appeler un fichier exe à partir d'une macro VBScript (les macros VBScript ne peuvent pas recevoir de paramètres). Vous pouvez écrire à la place et ce sera plus flexible. Appelez l'outil "DOS2UNIX.exe" depuis un complément sans avoir à l'ajouter à Service menu.

En Visual C++ à l'aide de la macro VBScript fournie :

  1. Ouvrez un fichier existant avec l'extension .dsm ou créez-en un.
  2. Collez le code précédemment donné dans le fichier.
  3. Dans Visual C++, procédez comme suit :
    1. Depuis Service menu, appuyez sur le bouton Paramètres.
    2. Cliquez sur le bouton Fichiers de macros et de compléments Languette.
    3. Cliquez sur le bouton Revoir chargez le fichier .dsm contenant la macro. Une fois dans le fichier .dsm, vous avez sélectionné Revoir boîte de dialogue, le fichier apparaîtra dans Modules complémentaires et macros liste des fichiers en utilisant la case cochée à côté.
    4. Cliquez sur le bouton Fermer continuer.

Maintenant, si vous ouvrez le fichier dans l'éditeur Visual C++ et enregistrez à partir du fichier Déposer menu, la macro appelée et tous les 0x0d seront supprimés du fichier ouvert. Étant donné que cela affectera tout fichier enregistré à partir de maintenant et appliqué à tout projet que vous ouvrirez ultérieurement, assurez-vous de désactiver la macro de Service menu utilisant Paramètres(décochez la case à côté de la macro).



voter en ligne (8)

L'inclusion d'un fichier C dans un autre fichier est légale, mais déconseillée, sauf si vous savez exactement pourquoi vous le faites et ce que vous essayez d'accomplir.
Je suis presque sûr que si vous postez ici la raison pour laquelle votre question sera communiquée à la communauté, vous trouverez une autre manière adaptée d'atteindre votre objectif (notez le "presque" car il est possible que ce soit une solution étant donné le contexte) .

En passant, j'ai raté la deuxième partie de la question. Si un fichier C est inclus dans un autre fichier et en même temps inclus dans un projet, vous risquez de rencontrer le problème des symboles en double, pourquoi lier des objets, c'est à dire que la même fonction sera définie deux fois (sauf s'ils sont statiques).

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

Cependant, en fonction des paramètres de votre fichier ou de votre projet, le fichier c inclus peut générer un fichier objet distinct. Une fois lié, cela peut entraîner des caractères doublement définis.

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

Cependant, il existe de nombreux environnements (à la fois les IDE et de nombreux Makefiles fabriqués à la main) qui s'attendent à ce que *.c soit compilé - si cela se produit, vous rencontrerez probablement des erreurs d'éditeur de liens dues à des symboles en double.

De manière générale, cette pratique doit être évitée.

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

Vous pouvez utiliser le compilateur gcc sous Linux pour lier deux fichiers avec une seule sortie. Disons que vous avez deux fichiers c, l'un est "main.c" et l'autre est "support.c". La commande pour connecter ces deux-là est donc

Gcc main.c support.c -o main.out

Ces deux fichiers seront associés à un seul main.out. Pour exécuter la sortie, la commande serait

./principale sortie

Si vous utilisez la fonction 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.

J'ai pensé partager une situation dans laquelle mon équipe a décidé d'inclure des fichiers .c. Notre architecte se compose principalement 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 essayé d'obtenir une couverture pour nos cas de test uniques, car le seul moyen d'implémenter ce code d'implémentation privé était indirectement via l'interface de message commune. Avec certaines caractéristiques des travailleurs sur les genoux de la pile, cela s'est avéré être un cauchemar pour assurer une couverture adéquate.

L’inclusion de fichiers .c nous a donné l’opportunité d’accéder au rouage de la machine, ce qui était amusant à tester.

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

Je ne sais pas quel programme vous utilisez avec le fichier .prj. Si vous utilisez quelque chose comme "make" ou Visual Studio ou autre, assurez-vous simplement de le définir sur une liste de fichiers qui doivent être compilés sans aucun fichier qui ne peut pas être compilé indépendamment.

Utilisée correctement, cette méthode peut être utile.

Disons que vous disposez d'un sous-système critique complexe avec une interface publique assez petite et de nombreux codes d'implémentation non implémentés. Le code comporte plusieurs milliers de lignes, des centaines de fonctions privées et un certain nombre de données privées. Si vous travaillez avec des systèmes embarqués non triviaux, vous êtes probablement confronté à cette situation assez souvent.

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

Avec C, vous avez beaucoup à perdre en faisant cela. Presque tous les outils fournissent des optimisations décentes 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 seul module source C, vous obtiendrez -

    Améliorations des performances et de la taille du code – Dans de nombreux cas, les appels de fonction seront intégrés. Même sans incrustation, le compilateur a la capacité de produire du code plus efficace.

    Les données de niveau de canal et de fonction sont masquées.

    En évitant la pollution des espaces de noms et ses conséquences, vous pouvez utiliser des noms moins encombrants.

    Compilation et communication plus rapides.

Mais vous vous retrouvez également dans un désordre impie lorsqu'il s'agit d'éditer ce fichier, et vous perdez la modularité implicite. Ce problème peut être surmonté en divisant le code source en plusieurs fichiers et en les incluant dans une seule unité de compilation.

Cependant, vous devez imposer certaines conventions pour y faire face. Dans une certaine mesure, cela dépendra 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 toujours le faire.

    Avoir un fichier .c principal qui inclut tous les fichiers .c enfants. Cela peut également inclure du code pour l'interface ouverte.

    Utilisez les protections du compilateur pour empêcher les en-têtes privés et les modules sources d'être inclus par les modules de compilation externes.

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

    Conservez une distinction conceptuelle entre les fichiers .c et .h. Cela utilise les conventions existantes. La différence est que vous aurez beaucoup d’annonces statiques dans vos en-têtes.

    Si votre chaîne d'outils n'impose rien, vous ne devez pas spécifier de fichiers d'implémentation privés comme .c et .h. Si vous utilisez des gardes activées, elles ne généreront pas de code et n'introduiront aucun nouveau nom (vous risquez ainsi de vous retrouver avec des segments vides). L'énorme avantage est que d'autres outils (comme les IDE) géreront ces fichiers en conséquence.

C'est bon? oui, ça va compiler

est-ce recommandé ? non - les fichiers .c sont compilés en fichiers .obj, qui sont liés après compilation (par l'éditeur de liens) dans un exécutable (ou une bibliothèque), il n'est donc pas nécessaire d'inclure un fichier .c dans un autre. Au lieu de cela, vous souhaiterez probablement créer un fichier .h qui répertorie les fonctions/variables disponibles dans un autre fichier .c et inclure le fichier .h



2024 wisemotors.ru. Comment ça fonctionne. Fer. Exploitation minière. Crypto-monnaie.