mikrocontroller.net

Forum: Compiler & IDEs include-wächter


Autor: Hd Schondelmaier (cosin)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hd Schondelmaier (cosin)
Datum:

Bewertung
0 lesenswert
nicht 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 ???

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hd Schondelmaier (cosin)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <stdint.h>

typedef struct {
    uint8_t test1;
    uint8_t test2;
} SomeStruct;

main.c
#include <stdint.h>
#include "struct.h"

uint8_t var1;
SomeStruct var2;

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hd Schondelmaier (cosin)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: A. W. (uracolix)
Datum:

Bewertung
0 lesenswert
nicht 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*/urac...

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).

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.