Organisation von C-Dateien

Lesezeit: 6 Minuten

Benutzer-Avatar
Kyle Cronin

Ich bin es gewohnt, meine gesamte Codierung in einer C-Datei durchzuführen. Ich arbeite jedoch an einem Projekt, das so groß ist, dass es unpraktisch wird. Ich habe sie zusammen #eingeschlossen, aber ich bin auf Fälle gestoßen, in denen ich einige Dateien mehrmals #einschließe usw. Ich habe von .h-Dateien gehört, bin mir aber nicht sicher, was ihre Funktion ist (oder warum 2 Dateien zu haben ist besser als 1).

Welche Strategien sollte ich anwenden, um meinen Code zu organisieren? Ist es möglich, “öffentliche” Funktionen von “privaten” Funktionen für eine bestimmte Datei zu trennen?

Diese Frage löste meine Anfrage aus. Die Datei tea.h verweist nicht auf die Datei tea.c. Weiß der Compiler, dass jede .h-Datei eine entsprechende .c-Datei hat?

Benutzer-Avatar
Schule

Sie sollten .h-Dateien als betrachten Schnittstellendateien Ihrer .c-Datei. Jede .c-Datei repräsentiert ein Modul mit einer bestimmten Menge an Funktionalität. Wenn Funktionen in einer .c-Datei von anderen Modulen (dh anderen .c-Dateien) verwendet werden, fügen Sie den Funktionsprototypen in die .h-Schnittstellendatei ein. Indem Sie die Schnittstellendatei in Ihre ursprüngliche Modul-.c-Datei und jede andere .c-Datei, in der Sie die Funktion benötigen, einfügen, machen Sie diese Funktion für andere Module verfügbar.

Wenn Sie eine Funktion nur in einer bestimmten .c-Datei (nicht in einem anderen Modul) benötigen, deklarieren Sie ihren Geltungsbereich als statisch. Das bedeutet, dass es nur innerhalb der c-Datei aufgerufen werden kann, in der es definiert ist.

Gleiches gilt für Variablen, die in mehreren Modulen verwendet werden. Sie sollten in die Header-Datei kommen und dort mit dem Schlüsselwort ‘extern’ gekennzeichnet werden. Hinweis: Bei Funktionen ist das Schlüsselwort ‘extern’ optional. Funktionen werden immer als ‘extern’ betrachtet.

Die Inklusionswächter in Header-Dateien helfen dabei, dieselbe Header-Datei nicht mehrmals einzufügen.

Zum Beispiel:

Modul1.c:

    #include "Module1.h"

    static void MyLocalFunction(void);
    static unsigned int MyLocalVariable;    
    unsigned int MyExternVariable;

    void MyExternFunction(void)
    {
        MyLocalVariable = 1u;       

        /* Do something */

        MyLocalFunction();
    }

    static void MyLocalFunction(void)
    {
      /* Do something */

      MyExternVariable = 2u;
    }

Modul1.h:

    #ifndef __MODULE1.H
    #define __MODULE1.H

    extern unsigned int MyExternVariable;

    void MyExternFunction(void);      

    #endif

Modul2.c

    #include "Module.1.h"

    static void MyLocalFunction(void);

    static void MyLocalFunction(void)
    {
      MyExternVariable = 1u;
      MyExternFunction();
    }

Versuchen Sie, jede .c-Datei auf einen bestimmten Funktionsbereich zu konzentrieren. Verwenden Sie die entsprechende .h-Datei, um diese Funktionen zu deklarieren.

Jede .h-Datei sollte einen „Header“-Schutz um ihren Inhalt haben. Zum Beispiel:

#ifndef ACCOUNTS_H
#define ACCOUNTS_H
....
#endif

Auf diese Weise können Sie “accounts.h” so oft einfügen, wie Sie möchten, und das erste Mal, wenn es in einer bestimmten Kompilierungseinheit angezeigt wird, ist das einzige, das tatsächlich seinen Inhalt einzieht.

Benutzer-Avatar
Adam Davis

Compiler

Sie können ein Beispiel eines C-Moduls unter diesem Thema sehen – Beachten Sie, dass es zwei Dateien gibt – den Header tea.h und den Code tea.c. Sie deklarieren alle öffentlichen Definitionen, Variablen und Funktionsprototypen, auf die andere Programme zugreifen sollen, im Header. In Ihrem Hauptprojekt werden Sie #include und dieser Code kann nun auf die Funktionen und Variablen des Tea-Moduls zugreifen, die im Header erwähnt werden.

Danach wird es etwas komplexer. Wenn Sie Visual Studio und viele andere IDEs verwenden, die Ihren Build für Sie verwalten, ignorieren Sie diesen Teil – sie kümmern sich um das Kompilieren und Verknüpfen von Objekten.

Linker

Wenn Sie zwei separate C-Dateien kompilieren, erzeugt der Compiler einzelne Objektdateien – also wird main.c zu main.o und tea.c zu tea.o. Die Aufgabe des Linkers besteht darin, sich alle Objektdateien (Ihre main.o und tea.o) anzusehen und die Referenzen abzugleichen. Wenn Sie also eine tea-Funktion in main aufrufen, ändert der Linker diesen Aufruf so, dass er tatsächlich das Recht aufruft Funktion im Tee. Der Linker erzeugt die ausführbare Datei.

Da ist ein tolle Anleitung das näher auf dieses Thema eingeht, einschließlich des Umfangs und anderer Probleme, auf die Sie stoßen werden.

Viel Glück!

-Adam

Benutzer-Avatar
Dennis Phillips

Ein paar einfache Regeln für den Anfang:

  1. Setzen Sie diese Deklarationen, die Sie “öffentlich” machen möchten, in die Header-Datei für die C-Implementierungsdatei, die Sie erstellen.
  2. #include nur Header-Dateien in die C-Datei, die zur Implementierung der C-Datei benötigt werden.
  3. Header-Dateien nur dann in eine Header-Datei aufnehmen, wenn dies für die Deklarationen in dieser Header-Datei erforderlich ist.

  4. Verwenden Sie die von Andrew beschriebene Methode include guard ODER use Einmal #Pragma wenn der Compiler es unterstützt (was dasselbe tut – manchmal effizienter)

Benutzer-Avatar
smh

Um deine Zusatzfrage zu beantworten:

Diese Frage löste meine Anfrage aus. Die Datei tea.h verweist nicht auf die Datei tea.c. Weiß der Compiler, dass jede .h-Datei eine entsprechende .c-Datei hat?

Der Compiler befasst sich nicht primär mit Header-Dateien. Jeder Aufruf des Compilers kompiliert eine Quelldatei (.c) in eine Objektdatei (.o). Hinter den Kulissen (dh in der make Datei oder Projektdatei) wird eine dieser äquivalente Befehlszeile generiert:

compiler --options tea.c

Die Quelldatei #includes alle Header-Dateien für die Ressourcen, auf die es verweist, wodurch der Compiler Header-Dateien findet.

(Ich beschönige hier einige Details. Es gibt eine Menge über das Erstellen von C-Projekten zu lernen.)

Benutzer-Avatar
David L Morris

Neben den oben gegebenen Antworten besteht ein kleiner Vorteil der Aufspaltung Ihres Codes in Module (separate Dateien) darin, dass Sie, wenn Sie globale Variablen benötigen, deren Gültigkeitsbereich auf ein einzelnes Modul beschränken können, indem Sie das Schlüsselwort ‘ statisch’. (Sie könnten dies auch auf Funktionen anwenden). Beachten Sie, dass sich diese Verwendung von „static“ von der Verwendung innerhalb einer Funktion unterscheidet.

Benutzer-Avatar
1800 INFORMATIONEN

Ihre Frage macht deutlich, dass Sie nicht wirklich viel ernsthafte Entwicklung betrieben haben. Der übliche Fall ist, dass Ihr Code im Allgemeinen viel zu groß ist, um in eine Datei zu passen. Eine gute Regel ist, dass Sie die Funktionalität in logische Einheiten (.c-Dateien) aufteilen und jede Datei nicht mehr enthalten sollte, als Sie gleichzeitig leicht in Ihrem Kopf behalten können.

Ein bestimmtes Softwareprodukt enthält dann im Allgemeinen die Ausgabe von vielen verschiedenen .c-Dateien. Dies geschieht normalerweise so, dass der Compiler eine Reihe von Objektdateien erzeugt (in Unix-Systemen “.o”-Dateien, VC generiert .obj-Dateien). Es ist der Zweck des “Linkers”, diese Objektdateien in die Ausgabe (entweder eine gemeinsam genutzte Bibliothek oder eine ausführbare Datei) zusammenzusetzen.

Im Allgemeinen enthalten Ihre Implementierungsdateien (.c) tatsächlichen ausführbaren Code, während die Header-Dateien (.h) die Deklarationen der öffentlichen Funktionen in diesen Implementierungsdateien enthalten. Sie können ganz einfach mehr Header-Dateien als Implementierungsdateien haben, und manchmal können Header-Dateien auch Inline-Code enthalten.

Es ist im Allgemeinen ziemlich ungewöhnlich, dass sich Implementierungsdateien gegenseitig enthalten. Es empfiehlt sich sicherzustellen, dass jede Implementierungsdatei ihre Bedenken von den anderen Dateien trennt.

Ich würde Ihnen empfehlen, die Quelle für den Linux-Kernel herunterzuladen und anzusehen. Es ist ziemlich umfangreich für ein C-Programm, aber gut in separate Funktionsbereiche unterteilt.

1369530cookie-checkOrganisation von C-Dateien

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy