Hallo, wie verhindere ich doppel-Includierungen bei Verwendungung mehrer C-Files, ohne den C-Code jedes mal zu änderen wenn ich ein bereits geschriebenes "Programm" bzw. Funktionen verwenden möchte. Danke für die Hilfe. Gruß Harri Verwende IAR und manchmal ICC
Wenn man in der ersten Include-Datei ein Makro definiert, kann man in allen folgenden mit #ifdef abfragen, ob das entsprechende Makro schon definiert und somit die Datei schon eingebunden wurde. #ifdef und #ifndef sind Standard-C-Elemente.
Im Header schreibst Du jeweils #ifdef MEIN_HEADER_NAME #define MEIN_HEADER_NAME ... // der Rest des Headers #endif C-Dateien solltest Du an keiner Stelle inkludieren. Das ist sehr, sehr, sehr, .... (n+1 mal, mit n->oo) schlechter Stil.
also im "main"-Teil z.B #include "temp.c" und #include "lcd.c" einfügen und dann im alten File temp.c , da dieses auch das lcd.c verwendet : #ifndef #include "lcd.c" einfügern, damit in main.c nicht zweimal lcd.c includiert wird?
eher anders herum: in der main.c das #ifndef benutzen. Ausprobieren könnte helfen...
Wie schlechter Stil? Ich dachte der Vorteil von C ist die Wiederverwendbarkeit von bereits geschriebenem Code? Ist es dann besser per Copy and Paste alte Teile bzw. Methoden zu integrieren? Gruß Harri
Ingo hat recht. Das macht man nicht so. .c-Dateien werden nicht nie niemals nirgendwo inkludiert. Dazu gibt es makefiles und einen Linker. IAR sollte dazu eine Projektverwaltung zur Verfügung stellen, die im Handbuch beschrieben sein sollte.
Hallo! Für das direkte Einfügen von Dateien per Include, auch wenn es sich dabei nicht um *.h Dateien handelt, muss ich mal eine Lanze brechen. Auf großen System ist es angebracht und zeugt von gutem Stil, wenn nur die Header eingefügt werden. Der Linker erledigt dann den Rest. Im Bereich der Controller jedoch gibt es Compiler, die nicht über Modulgrenzen hinweg optimieren können, so wie es z.B. beim cc5x gegeben ist. Hier ist dann ein direktes Include von C-Dateien erlaubt, wobei ggfs. auch Schleifen von Include-Anweisungen bei #ifdef/#define/#endif notwendig ist. Gruß, Rainer
@Rainer: Kannst Du das bitte an einem Beispiel erklären. Oder hast du Referenzen dazu (Docs, Application Notes oder ähnliches)?
"Im Bereich der Controller jedoch gibt es Compiler, die nicht über Modulgrenzen hinweg optimieren können, so wie es z.B. beim cc5x gegeben ist. Hier ist dann ein direktes Include von C-Dateien erlaubt" Dann sollte man trotzdem die Deklarationen in *.h-Files schreiben und diese zu Anfang includieren und die eigentlichen *.C-Quelltexte dahinter. Peter
Ingos Beschreibung ist vollkommen zutreffend. Die Dinger heißen auch Headerguards. Und natürlich schreibt man diese in das jeweils zu inkludierende File und nicht etwa dort, wo das File inkludiert wird... Denn ein Header soll selbst prüfen, ob es schon einmal eingebunden wurde. Rahuls Darstellung muss ich scharf widersprechen. Das Inkludieren von c-Files im Sinne von "Code-Reuse" ist nicht zu empfehlen, wenn nicht die von Rainer beschriebenen Einschränkungen gelten. Modulare Programmierung ist das jedenfalls nicht mehr, weil es alle Quelltextdateien über Gebühr hinaus miteinander verknüpft. Auf "normalen" Systemen sollten Headers inkludiert werden und der entsprechende Modulcode wird als Objektdatei dagegen gelinkt.
Hi, also im jeweiligen .h file ein #define und dann nach dem define abfragen. Wenn das nich definiert is dann #include...hab ich das richtig verstanden? Bsp: in der lcd.h: /.... #define LCD /.... in der main.c: #ifndef LCD #include "lcd.h" //... #endif //....
Hallo Tom, ich finde es schöner so: Im Header: lcd.h #ifndef LCD_H #define LCD_H /... #endif und in der main.c: #include "lcd.h" Das hat den Charme, dass man lcd.hh einbinden kann, wo man es braucht. Man muß sich gar keine Gedanken mehr machen, wer es sonst noch eingebunden haben könnte. Sicher funktioniert Deine Lösung auch, aber logischer erscheint es mir, in der entsprechenden Header-Datei dafür zu sorgen, dass sie nicht mehrfach aufgerufen werden kann. Gruß, Nils
Hi Nils, achso jetz glaub ich hab ich kapiert, wie ihr das meint :). Wenn die header schon einmal eingebunden wurde existiert ja das LCD_H schon, also überspringer er das beim nächsten #include "lcd.h". Aber ist es eigentlich nicht egal ob ein Header 2 mal includiert wird? Wo gibts da "probleme" wenn ich jetz z.b. ein projekt aus 3 c-files hab und in jedem c-file das "lcd.h" includiere? Ich glaub ich hab da was falsch verstanden :)... Grüße
Also vielleicht mal zum prinzipiellen Verständnis, das ist mir nämlich auch lange Zeit schwer gefallen, zu verstehen. Wenn ein Projekt kompiliert wird, müssen alle Funktionen und ihre Aufrufsparameter bekannt sein. Hast du nur eine Datei und definierst die Hilfsfunktionen vor der main(), so ist das kein Problem - alle in der main() verwendeten Funktionen sind beim Durchlaufen des Quellcodes bekannt, damit passt das. Jetzt kommen die Header ins Spiel. Da du deinene Code zwecks Übersicht (und für die Wiederverwendung) normalerweise in extra Dateien schreibst, gibts ein Problem. Denn in der main() werden Funktionen verwendet, die in einer anderen Datei definiert sind. Zwar könnten die Dateien vorher geparst und nach verwendeten Funktionen durchsucht werden, aber das geschieht nicht. Denn neben deinen .c-Files (die du dir mit nem Texteditor anschauen kannst) gibts auch .o (also Objekt-Files), die schon kompiliert worden sind und nicht so einfach mit nem Texteditor angeschaut werden können. Das ist wie ne Black Box - da sind möglicherweise tolle Funktionen drin, aber als Mensch weisst du nix davon, da die Datei nur vom Computer gelesen werden kann. Also gibts die .h - Files. Hier steht drin, welche Funktionen mit welchen Parametern dem Programm zur Verfügung stehen. Wenn das Programm mit der includierten .h kompiliert wird, freut sich der Compiler, weil er weiss, die Funktionen gibts irgendwo. Deine .c-Files musst du nicht includen - die fügst du einfach nur so ins Projekt ein. Denn die werden zwar mitkompiliert, aber weiter nix. Die könntest du auch auf nem anderen PC kompilieren und dann als Object-Files einbinden. Denn der Code interessiert erst mal ned, solang ned Fehler drin sind, der Compiler weisst ja welche Funktionen in dem Code vorhanden sein müssen und ist zufrieden. Erst zum Schluss passiert das Zusammenfügen: Der Linker bastelt aus den fertig kompilierten Dateien dein Programm. Er verbindet die kompilierten Module mit deinem main() und wenn alle Funktionen vorhanden sind, die laut Header-Dateien vorhanden sein sollten, läuft das Programm auch. Jetzt noch zu deiner Frage, warum du "nicht einfach so" mehrmals eine Header-Datei includen kannst. Stell dir ein include wie ein Copy&Paste vor. Du hast ne Headerdatei mit z.B."int funktion(int, char);" und fügst die zweimal per Include ein, dann bekommst du sowas: int funktion(int, char); int funktion(int, char); Zwar schauen die gleich aus, aber der Compiler ist dumm, er sieht zwei gleichnamige Funktionen und weiss nicht was er machen soll. Deswegen hilf ihm und schreib deine Header wie folgt: #ifndef _FUNKTON_H #define _FUNKTION_H int funktion(int, char); #endif Damit wird beim ersten include geschaut: Ist _FUNKTION_H bereits definiert? Ist es nicht, deswegen weitermachen. Als erstes wird dann _FUNKTION_H definiert, dann der weitere Text geparst. Ab dem zweiten Include ist _FUNKTION_H bereits definiert, also überspringe folgenden Code. Bedeutet: Der Compiler weiss ja bereits, welche Funktionen er verwenden kann, einem intelligenten Menschen muss man ja auch nicht 10x sagen, dass sein Schnürsenkel offen ist, das sollte er bereits beim ersten Hinweis beheben. Hoffe, das wurde jetzt ein wenig verständlicher...
Es haben hier beide Meinungen etwas für sich. das #ifndef GAXI #include "GAXi.h" #endif hat man früher (vor 1990) verwendet, um zu verhindern, daß der Compiler das headerfile noch einmal einliest. Das hat früher viel Zeit beim Compilieren erspart. Das war allerdings in Zeiten, als 2MB noch eine extreme Seltenheit waren und ein full compile auf einem 386DX33 (IBM Model95 um über 7000) bis zu 20 Minuten gedauert hat...
Aber das Inkludieren von Headerfiles hat mit dem Kompilieren erstmal nichts zu tun, da Headers normalerweise (*) nur Deklarationen, aber keine Definitionen enthalten. Ein vernünftiger Compiler/Make baut nur die Quellen neu, die gegenüber ihrem Objectfile neuer sind. Headerguards dienen nicht dazu bedingte Kompilationen zu provozieren (was mit #ifdef/#ifndef natürlich auch geht). Sie sollen einzig und allein das mehrfache Inkludieren von Headerfiles verhindern, da dieses zwangsläufig zu einem Fehler (doppelte Deklaration) führen würde. Narrensicher beschrieben von Ithamar. (*) Es gibt Ausnahmen.
Hi ithamar, danke für die ausführliche Info :). Ich dachte immer der Compiler macht das alles alleine u desw is des sinnlos ;)..naja man lernt nie aus. Najo werd jetz mal meine ganzen Header in ne #ifndef struktur packen :). Grüße
Also gut, vielen Dank. Hab noch mal nachgesehen. Ich hab keine *.c Files includiert sondern auch nur meine dazu erstellten *.h Dateien. War also doch nicht alles so falsch was ich so geschrieben hab. Der Compiler beschwerte sich darüber, dass ich bei der neuen "main" die #include <io430x14x.h> verwende und bei der älteren lcd.c und zugehörigen lcd.h noch von früher die #include <msp430x14x.h> drin hatte. Da gibts Überschneidungen die ich jetzt wohl umgehen kann. Danke, Gruß Harri
Hallo, inkludieren von C Quellcode (*.c Datei) kann durchaus sinnvoll sein. Zum einen habt ihr dann nur eine Instanz eurer Software; nur die wird getestet und ggf. verändert. Nötig ist dies jedoch nur, wenn ihr eine schlechte Prjektumgebung wie den Platformbuilder für WinCe nutzen müsst der den Adressraum in verschiedene Bereiche segmentiert. Es gibt dann mehrere Instanzen der Software die sich gegenseitige abgrenzen. Dann ist der Code im Bootloader nicht mehr im Image zugänglich und die zusätzlichen Softwareprojekte (z.B. Konsolenanwendungen) brauchen den Treiber nochmals! In dieser WinCE Architektur muss der Quellcode also dreifach vorhanden sein. Tschüß
Hä? Das erscheint mir reichlich wirr. Wieso sollte man bei normaler Arbeit mit einem C-Compiler und Linker nicht "nur eine Instanz [der] Software" haben? Was bitte ist für Dich eine solche "Instanz" und woran machst Du das fest? Und was mag ein Treiber mit dem includieren von C-Quelltext zu tun haben, und vor allem: Was hat das alles mit Windows CE zu tun, das wie jede andere Windows-Version auch bekanntlich dynamisch linken kann?
@Rufus: Windows CE ist bekanntlich von Micros~1. Was erwartest Du.
Da das hier alles ausführlich erklärt wird, kommt jetzt auch noch "mein Senf": Man darf in eigenem Code keine führenden Unterstriche bei der Namenwahl verwenden. Das verbietet der Standard und ist nur den Entwicklern des Compilers und denen der Library gestattet.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.