Hallo, mir ist klar, dass include-Wächter-Konstrukte verhindern, dass Variablen oder Klassen doppelt angelegt werden. Aber wie arbeitet der Compiler, wenn in der Headerdatei defines stehen, die er in mehreren C-Dateien kennen muss? Hier ein Fall: file1.c: #include file2.h #include file1.h void func(durchmesser) { kreis = durchmesser * PI; } file2.c: #include file1.h #include file2.h void func(umfang) { durchmesser = umfang / PI; } file1.h: #ifndef FILE1_H #define FILE1_H #define PI 3.14 #endif Dieser Code funktioniert, aber mir ist nicht klar, warum eigentlich. Wenn file1.c compiliert wird, dann hat der Compiler auch das PI-define. Wenn anschliessend file2.c compiliert wird, kennt er doch das PI-Define nicht. Oder wenn ja, woher? Merkt sich ein Compiler alle defines, die er in einem Compilerlauf erkannt hat und stellt sie dann ALLEN Files zur Verfügung? In allen Fachbuechern liest man nur, wie wichtig die Include-Wächter sind, aber irgendwie muss der Compiler nach Regeln arbeiten, die den include-Wächter eigentlich wieder aushebeln. (Getestet wurde das mit einem PIC-Compiler von HiTech) Bin dankbar für Infos!
Dieser Code wird bestimmt nicht funktionieren da du keine main hast. Du inkludierst alles was du so benötigst vor deiner main. Includes sind nur einfache Textersetzungen. Somit steht dein Define dann auch in der Datei an einer Stelle bevor es zum ersten mal genutzt wird. In dem Fall hat sogar der Compiler absolut garnix damit zu tun, da es bei für include und define der präprozessor zuständig ist.
Ja, die main hab ich nicht beschrieben. Der Preprozessor setzt den Headerfile-Text in file1.c ein. Danach nimmt er file2.c und setzt wieder den Headerfile-Text ein. Diesmal aber ohne das define. Genau hier fehlt nun das "#define PI 3.14", wenn der Preprozessor file1.c vor file2.c bearbeitet. Wenn nun der Compiler die Files uebersetzt, muss er doch meckern, weil PI in file2.c nicht definiert ist. Vielleicht liegt mein Problem im Verständis der Abarbeitungsreihenfolge. Oder arbeitet der Compiler+Preprozessor ein Projekt vom main her auf ???
Hd Schondelmaier schrieb: > Der Preprozessor setzt den Headerfile-Text in file1.c ein. > Danach nimmt er file2.c und setzt wieder den Headerfile-Text ein. > Diesmal aber ohne das define. Wie kommst du darauf? Das Übersetzen von file2.c ist ein ganz neuer Vorgang, der wieder bei Null startet, FILE1_H ist dort also nicht definiert. Der Include-Wächter verhindert nur das mehrfache Inkludieren innerhalb einer C-Datei. Bei komplexeren Projekten passiert das nämlich fast schon zwangsläufig.
OK, vielleicht fehlt mir der Sinn für komplexe Projekte, wenn aber für ein einziges C-File die Header-Includes so undurchsichtig sein können, ist das nicht ein klares Zeichen für einen unsauberen Programmierstil des Entwicklers? Oder gebt mir mal ein Beispiel, bei dem dieser Wächter wirklich notwendig ist. Sollte man nicht besser die Softwarestruktur überarbeiten, anstelle das "Chaos" mit Wächtern zu unterdrücken? Bin gespannt, auf ein Beispiel.
Hd Schondelmaier schrieb: > vielleicht fehlt mir der Sinn für komplexe Projekte, wenn aber für ein > einziges C-File die Header-Includes so undurchsichtig sein können, ist > das nicht ein klares Zeichen für einen unsauberen Programmierstil des > Entwicklers? Nein, die Mehrfachinkludes ergeben sich dagegen eher gerade durch einen sauberen Programmierstiel. Es ist nämlich ein sauberer Programmierstiel, explizit das zu inkludieren, was man braucht und sich nicht darauf zu verlassen, dass das schon irgendwie indirekt über andere Inkludes mit rein kommt. Einfaches Beispiel: struct.h
1 | #include <stdint.h> |
2 | |
3 | typedef struct { |
4 | uint8_t test1; |
5 | uint8_t test2; |
6 | } SomeStruct; |
main.c
1 | #include <stdint.h> |
2 | #include "struct.h" |
3 | |
4 | uint8_t var1; |
5 | SomeStruct var2; |
Hd Schondelmaier schrieb: > vielleicht fehlt mir der Sinn für komplexe Projekte, wenn aber für ein > einziges C-File die Header-Includes so undurchsichtig sein können, ist > das nicht ein klares Zeichen für einen unsauberen Programmierstil des > Entwicklers? Nein, es ist das Gegenteil. Programmierer sind faule Menschen, sie schreiben nur soviel wie nötig. Wenn z.B. etwas im Header a.h und b.h benötigt wird, dann schreiben sie das nicht doppelt, sondern lagern es in Header c.h aus., der dann in a.h und b.h includiert wird. Wenn Du in Deinem Programm nun a.h und b.h benötigst, würde dadurch c.h zweimal includiert werden. Und dann kommt eben das #ifndef ins Spiel und verhindert das. Z.B. includieren viele Header auch das stdint.h Peter
Ich bin auch nicht fuers "viel schreiben", bisher hab ich es strikt vermieden, in Headerfiles weitere Header einzubinden. Aber gut, das Beispiel zeigt mir, dass es vielleicht doch Fälle gibt, die den "Wächter" notwendig machen. Vielen Dank für diese Tipps!
Die Include-Waechter sollten m.E. "verpflichtend" in allen Coding-Guidelines stehen. Falls mal jemand seinen aktuellen Include-Graphen vor Augen haben will, dem hilft vielleicht dieses kleine Python-Script weiter. Es erzeugt ein Graphenfile fuer graphviz. Der Aufruf ist im Kommentar zu sehen. http://cvs.savannah.gnu.org/viewvc/*checkout*/uracoli/Tools/h2dot.py?root=uracoli&revision=1.3&content-type=text%2Fplain Das Ergebnis sieht dann in etwas so aus: http://www.nongnu.org/uracoli/manual/dev/radio.dot.png Ob man so einem Graphen nun eine grosse Bedeutung beimisst oder nicht, auf alle Faelle ist es sicher kein schlechtes Zeichen, wenn alle Pfeile in eine Richtung zeigen ;-) (Wenn nicht hat man u.U. zirkulare Abhaengigkeiten und man muss die Files in der "richtigen Reihenfolge" einbinden).
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.