Forum: Compiler & IDEs include-wächter


von Hd S. (cosin)


Lesenswert?

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!

von martin (Gast)


Lesenswert?

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.

von Hd S. (cosin)


Lesenswert?

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 ???

von Stefan E. (sternst)


Lesenswert?

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.

von Hd S. (cosin)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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;

von Peter D. (peda)


Lesenswert?

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

von Hd S. (cosin)


Lesenswert?

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!

von A. W. (uracolix)


Lesenswert?

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
Noch kein Account? Hier anmelden.