www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Verhindern von Doppel-Include


Autor: Harri (Gast)
Datum:

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

Autor: Rahul (Gast)
Datum:

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

Autor: Ingo (Gast)
Datum:

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

Autor: Harri (Gast)
Datum:

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

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eher anders herum: in der main.c das #ifndef benutzen.
Ausprobieren könnte helfen...

Autor: Harri (Gast)
Datum:

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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

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

Autor: Rainer (Gast)
Datum:

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

Autor: Dirk Dörr (dirkd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rainer:
Kannst Du das bitte an einem Beispiel erklären. Oder hast du Referenzen
dazu (Docs, Application Notes oder ähnliches)?

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Stromspannung (Gast)
Datum:

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

Autor: Tom (Gast)
Datum:

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

Autor: Nils (Gast)
Datum:

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

Autor: Tom (Gast)
Datum:

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

Autor: Ithamar Garbe (antimon)
Datum:

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

Autor: Mark Struberg (struberg)
Datum:

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

Autor: Stromspannung (Gast)
Datum:

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

Autor: Tom (Gast)
Datum:

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

Autor: Harri (Gast)
Datum:

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

Autor: Michael Jungnickl (Gast)
Datum:

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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

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

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rufus:

Windows CE ist bekanntlich von Micros~1. Was erwartest Du.

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

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

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.