Ist es in Ordnung (oder sogar empfohlen / bewährte Methode) für #include
eine .c
Datei in einer anderen .c
Datei?
111
Ist es in Ordnung (oder sogar empfohlen / bewährte Methode) für #include
eine .c
Datei in einer anderen .c
Datei?
Antworten:
Bei richtiger Anwendung kann dies eine nützliche Technik sein.
Angenommen, Sie haben ein komplexes, leistungskritisches Subsystem mit einer relativ kleinen öffentlichen Schnittstelle und viel nicht wiederverwendbarem Implementierungscode. Der Code umfasst mehrere tausend Zeilen, ungefähr hundert private Funktionen und ziemlich viele private Daten. Wenn Sie mit nicht trivialen eingebetteten Systemen arbeiten, werden Sie wahrscheinlich häufig genug mit dieser Situation umgehen.
Ihre Lösung wird wahrscheinlich geschichtet, modular und entkoppelt sein, und diese Aspekte können sinnvoll dargestellt und verstärkt werden, indem verschiedene Teile des Subsystems in verschiedenen Dateien codiert werden.
Mit C können Sie viel verlieren, wenn Sie dies tun. Fast alle Toolchains bieten eine anständige Optimierung für eine einzelne Kompilierungseinheit, sind jedoch in Bezug auf alles, was als extern deklariert wird, sehr pessimistisch.
Wenn Sie alles in ein C-Quellmodul packen, erhalten Sie -
Leistungs- und Codegrößenverbesserungen - Funktionsaufrufe werden in vielen Fällen eingebunden. Auch ohne Inlining hat der Compiler die Möglichkeit, effizienteren Code zu erstellen.
Daten und Funktionen auf Verbindungsebene werden ausgeblendet.
Vermeidung von Verschmutzung durch Namespaces und deren Folgen - Sie können weniger unhandliche Namen verwenden.
Schnellere Zusammenstellung und Verknüpfung.
Aber Sie bekommen auch ein unheiliges Durcheinander, wenn es darum geht, diese Datei zu bearbeiten, und Sie verlieren die implizite Modularität. Dies kann überwunden werden, indem die Quelle in mehrere Dateien aufgeteilt und diese eingeschlossen werden, um eine einzige Kompilierungseinheit zu erstellen.
Sie müssen jedoch einige Konventionen festlegen, um dies ordnungsgemäß zu verwalten. Diese hängen in gewissem Maße von Ihrer Toolchain ab, aber einige allgemeine Hinweise sind:
Fügen Sie die öffentliche Schnittstelle in eine separate Header-Datei ein - Sie sollten dies trotzdem tun.
Haben Sie eine Haupt-C-Datei, die alle Neben-C-Dateien enthält. Dies könnte auch den Code für die öffentliche Schnittstelle enthalten.
Verwenden Sie Compiler Guards, um sicherzustellen, dass private Header und Quellmodule nicht von externen Kompilierungseinheiten enthalten sind.
Alle privaten Daten und Funktionen sollten als statisch deklariert werden.
Behalten Sie die konzeptionelle Unterscheidung zwischen .c- und .h-Dateien bei. Dies nutzt bestehende Konventionen. Der Unterschied besteht darin, dass Ihre Header viele statische Deklarationen enthalten.
Wenn Ihre Toolchain keinen Grund dafür darstellt, benennen Sie die privaten Implementierungsdateien als .c und .h. Wenn Sie Include-Wachen verwenden, erzeugen diese keinen Code und führen keine neuen Namen ein (möglicherweise werden während der Verknüpfung einige leere Segmente angezeigt). Der große Vorteil ist, dass andere Tools (z. B. IDEs) diese Dateien angemessen behandeln.
quelle
Ist es o.k? Ja, es wird kompiliert
wird es empfohlen? no - .c - Dateien werden zu .obj - Dateien kompiliert, die nach dem Kompilieren (durch den Linker) in die ausführbare Datei (oder Bibliothek) verknüpft werden, sodass keine .c - Datei in eine andere aufgenommen werden muss. Was Sie wahrscheinlich stattdessen tun möchten, ist, eine .h-Datei zu erstellen, die die in der anderen .c-Datei verfügbaren Funktionen / Variablen auflistet und die .h-Datei enthält
quelle
Nein.
Abhängig von Ihrer Build-Umgebung (die Sie nicht angeben) stellen Sie möglicherweise fest, dass sie genau so funktioniert, wie Sie es möchten.
Es gibt jedoch viele Umgebungen (sowohl IDEs als auch viele handgefertigte Makefiles), in denen erwartet wird, dass * .c kompiliert wird. In diesem Fall treten wahrscheinlich Linkerfehler aufgrund doppelter Symbole auf.
Diese Praxis sollte in der Regel vermieden werden.
Wenn Sie die Quelle unbedingt einschließen müssen (und dies im Allgemeinen vermieden werden sollte), verwenden Sie ein anderes Dateisuffix für die Datei.
quelle
Ich dachte, ich würde eine Situation teilen, in der mein Team beschlossen hat, .c-Dateien aufzunehmen. Unsere Architektur besteht größtenteils aus Modulen, die über ein Nachrichtensystem entkoppelt sind. Diese Nachrichtenhandler sind öffentlich und rufen viele lokale statische Worker-Funktionen auf, um ihre Arbeit zu erledigen. Das Problem trat auf, als versucht wurde, eine Abdeckung für unsere Unit-Testfälle zu erhalten, da die einzige Möglichkeit, diesen privaten Implementierungscode auszuführen, indirekt über die öffentliche Nachrichtenschnittstelle bestand. Da einige Arbeiterfunktionen knietief im Stapel liegen, stellte sich heraus, dass dies ein Albtraum war, um eine angemessene Abdeckung zu erreichen.
Durch die Aufnahme der .c-Dateien konnten wir das Zahnrad in der Maschine erreichen, die wir testen wollten.
quelle
Sie können den gcc-Compiler unter Linux verwenden, um zwei c-Dateien in einer Ausgabe zu verknüpfen. Angenommen, Sie haben zwei c-Dateien, eine ist 'main.c' und eine andere ist 'support.c'. Der Befehl, diese beiden zu verbinden, lautet also
Auf diese Weise werden zwei Dateien mit einer einzigen Ausgabe main.out verknüpft. Um die Ausgabe auszuführen, lautet der Befehl
Wenn Sie die Funktion in main.c verwenden, die in der Datei support.c deklariert ist, sollten Sie sie in main auch mit der externen Speicherklasse deklarieren.
quelle
Die Erweiterung der Datei spielt für die meisten C-Compiler keine Rolle, daher funktioniert sie.
Abhängig von Ihren Makefile- oder Projekteinstellungen kann die enthaltene c-Datei jedoch eine separate Objektdatei generieren. Beim Verknüpfen kann dies zu doppelt definierten Symbolen führen.
quelle
Sie können .C- oder .CPP-Dateien ordnungsgemäß in andere Quelldateien einfügen. Abhängig von Ihrer IDE können Sie Doppelverknüpfungen normalerweise verhindern, indem Sie sich die Eigenschaften der Quelldateien ansehen, die Sie einschließen möchten. Klicken Sie dazu mit der rechten Maustaste darauf und klicken Sie auf Eigenschaften, und deaktivieren / aktivieren Sie Kompilieren / Verknüpfen / Ausschließen vom Build oder einer beliebigen Option vielleicht. Oder Sie konnten die Datei nicht in das Projekt selbst aufnehmen, sodass die IDE nicht einmal weiß, dass sie existiert, und nicht versucht, sie zu kompilieren. Und mit Makefiles würden Sie die Datei einfach nicht zum Kompilieren und Verknüpfen einfügen.
EDIT: Entschuldigung, ich habe es zu einer Antwort gemacht, anstatt auf andere Antworten zu antworten :(
quelle
Die C-Sprache verbietet diese Art von #include nicht, aber die resultierende Übersetzungseinheit muss noch gültig sein. C.
Ich weiß nicht, welches Programm Sie mit einer PRJ-Datei verwenden. Wenn Sie etwas wie "make" oder Visual Studio oder was auch immer verwenden, stellen Sie einfach sicher, dass Sie die Liste der zu kompilierenden Dateien ohne die Liste festlegen, die nicht unabhängig kompiliert werden kann.
quelle
Das Einfügen einer C-Datei in eine andere Datei ist legal, aber nicht ratsam, es sei denn, Sie wissen genau, warum Sie dies tun und was Sie erreichen möchten.
Ich bin mir fast sicher, dass, wenn Sie hier den Grund veröffentlichen, warum die Community hinter Ihrer Frage einen anderen geeigneteren Weg findet, um Ihr Ziel zu erreichen (bitte beachten Sie das "fast", da dies angesichts des Kontexts möglicherweise die Lösung ist ).
Übrigens habe ich den zweiten Teil der Frage verpasst. Wenn die C-Datei in einer anderen Datei enthalten ist und gleichzeitig in das Projekt aufgenommen wird, tritt wahrscheinlich ein Problem mit doppelten Symbolen auf, warum die Objekte verknüpft werden, dh dieselbe Funktion wird zweimal definiert (es sei denn, sie sind alle statisch).
quelle
Sie sollten einen Header wie diesen hinzufügen
Hinweis: Beide Dateien sollten an derselben Stelle abgelegt werden
Ich benutze dies in Codevison AVR für ATMEGA-Mikrocontroller und arbeite wirklich, aber es funktioniert nicht in normalen C-Sprachdateien
quelle