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
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).
Eine eigene Frage?
Dieser Thread ist über 17 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.