webentwicklung-frage-antwort-db.com.de

Einbinden einer C-Quelldatei in eine andere?

Ist es in Ordnung (oder sogar empfohlen/gute Praxis), #include .c Datei in einer anderen .c Datei? Was passiert, wenn sie in einer Projektdatei enthalten sind?

97
srujan

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 besteht aus mehreren tausend Zeilen, etwa hundert privaten Funktionen und einer Menge privater Daten. Wenn Sie mit nicht trivialen eingebetteten Systemen arbeiten, werden Sie wahrscheinlich häufig genug mit dieser Situation fertig.

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 dadurch viel verlieren. Fast alle Toolchains bieten eine anständige Optimierung für eine einzelne Kompilierungseinheit, sind jedoch in Bezug auf alles, was extern deklariert wird, sehr pessimistisch.

Wenn Sie alles in ein C-Quellmodul packen, erhalten Sie:

  • Performance- und Code-Größenverbesserungen - Funktionsaufrufe werden in vielen Fällen eingeblendet. Auch ohne Inlining hat der Compiler die Möglichkeit, effizienteren Code zu erstellen.

  • Link Level Daten & Funktion verstecken.

  • Vermeidung von Namensraumverschmutzung und deren Folge - Sie können weniger unhandliche Namen verwenden.

  • Schnellere Zusammenstellung und Verknüpfung.

Aber Sie bekommen auch ein unheiliges Durcheinander, wenn Sie diese Datei bearbeiten, und Sie verlieren die implizite Modularität. Dies kann überwunden werden, indem Sie die Quelle in mehrere Dateien aufteilen und diese zu einer einzigen Kompilierungseinheit zusammenfassen.

Sie müssen jedoch einige Konventionen auferlegen, um dies ordnungsgemäß zu verwalten. Diese hängen zum Teil von Ihrer Toolchain ab, aber einige allgemeine Hinweise sind:

  • Stellen Sie die öffentliche Schnittstelle in eine separate Header-Datei - Sie sollten dies trotzdem tun.

  • Haben Sie eine Haupt-C-Datei, die alle untergeordneten 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 eingeschlossen werden.

  • 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 auferlegt, dies nicht zu tun, benennen Sie die privaten Implementierungsdateien als .c und .h. Wenn Sie Include-Guards verwenden, erzeugen diese keinen Code und führen keine neuen Namen ein (möglicherweise werden während der Verknüpfung leere Segmente angezeigt). Der große Vorteil ist, dass andere Tools (z. B. IDEs) diese Dateien entsprechend behandeln.

106

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 der ausführbaren Datei (oder Bibliothek) miteinander verknüpft werden. Daher ist es nicht erforderlich, eine .c-Datei in eine andere aufzunehmen. Sie möchten wahrscheinlich stattdessen eine .h-Datei erstellen, in der die Funktionen/Variablen aufgeführt sind, die in der anderen .c-Datei verfügbar sind, und die .h-Datei einschließen

49
Steven A. Lowe

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), die das Kompilieren von * .c erwarten - in diesem Fall werden Sie wahrscheinlich aufgrund doppelter Symbole Linkerfehler bekommen.

In der Regel sollte diese Praxis vermieden werden.

Wenn Sie unbedingt den Quellcode angeben müssen (und dies generell vermeiden sollten), verwenden Sie ein anderes Dateisuffix für die Datei.

11

Ich dachte, ich würde eine Situation teilen, in der mein Team beschlossen hat, C-Dateien einzuschließen. Unsere Architektur besteht größtenteils aus Modulen, die über ein Nachrichtensystem entkoppelt sind. Diese Message-Handler 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 der einzige Weg, diesen privaten Implementierungscode auszuüben, indirekt über die öffentliche Nachrichtenschnittstelle erfolgte. Mit einigen knietiefen Arbeiterfunktionen im Stapel erwies sich dies als Albtraum, um eine ordnungsgemäße Abdeckung zu erreichen.

Das Einbeziehen der .c-Dateien ermöglichte es uns, das Zahnrad in der Maschine zu erreichen, die wir testen wollten.

9
Matthew Alford

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.

5
HS.

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

gcc main.c support.c -o main.out

Dadurch werden zwei Dateien mit einer einzigen Ausgabe verknüpft. Main.out Um die Ausgabe auszuführen, wird der Befehl ausgeführt

./main.out

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.

3
sumitroy

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 die gewünschten Eigenschaften der Quelldateien anzeigen, indem Sie mit der rechten Maustaste darauf klicken und auf Eigenschaften klicken und das Kontrollkästchen Kompilieren/Verknüpfen/Vom Build ausschließen oder eine andere Option deaktivieren vielleicht. Oder Sie könnten die Datei nicht in das Projekt selbst aufnehmen, so dass die IDE nicht einmal weiß, dass sie existiert und nicht versucht, sie zu kompilieren. Und mit Makefiles würden Sie die Datei einfach nicht hineinlegen zum kompilieren und verlinken.

BEARBEITEN: Sorry, ich habe es eine Antwort anstelle einer Antwort auf andere Antworten gemacht :(

2
MikeyPro

Die C-Sprache verbietet diese Art von #include nicht, aber die resultierende Übersetzungseinheit muss immer noch gültig sein.

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.

1

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 die Community, wenn Sie den Grund für Ihre Frage hier posten, einen anderen angemesseneren Weg findet, um Ihr Ziel zu erreichen (bitte beachten Sie das "Fast", da dies möglich ist die Lösung im gegebenen Kontext).

Übrigens habe ich den zweiten Teil der Frage verpasst. Wenn die C-Datei in einer anderen Datei enthalten ist und gleichzeitig im Projekt enthalten ist, werden Sie wahrscheinlich ein Problem mit doppelten Symbolen haben, warum die Objekte verknüpft werden, d. H. Dieselbe Funktion wird zweimal definiert (sofern sie nicht alle statisch sind).

0
Ilya