mikrocontroller.net

Forum: Compiler & IDEs struct in header auslagern.


Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo !

Versuche gerade Funktionen in ein paar Header zu verpacken.
(die sich auch untereinanader einbinden)

Ich suche jetzt ein paar "Regeln",
da hier im Forum anscheinend nur sonderfälle (bis auf 
http://www.mikrocontroller.net/articles/Funktionen...) ) 
behandelt werden.

- Modulübergreifende Funktionen müssen als Funktionsrumpf in das 
Header-File.
- Globale Variablen werden im C-File Definiert (erstellt, Platz 
reserviert), und im Header-File mit "extern" Deklariert (bekannt 
gemacht).

Ich bekomme keine  Compiler-Fehlermeldungen in Richtung "redefinition",
selbst wenn ein Header Mehrfach eingebunden wird.

---

Wenn ich structs, enums und typedefs auslagern möchte muss ich diese 
bedingte Kompilierung benutzen :

#ifndef _test
#define _test
   Code
#endif

Gibt es da keinen eleganteren Weg wie bei der Variablen-Definition und 
extern Deklaration ???

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle Funktionen, Variablen, und includs kommen in das C File

Alle Definitionen, Strukturen und Definitionen ins H File.

Werden die Variablen auch in anderen C Files benötigt kommen die auch 
mit einem extern in das H File

Autor: Andreas H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wann muss man einer Funktion ein "static" voranstellen?

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine einfache Möglichkeit (ähnlich Deiner) ist

    #ifndef _YourHeaderFileName_
    #ifndef _YourHeaderFileName_

am Anfang Deiner Header-Datei und

    #endif

am Ende der Header-Datei ( =: Makro-Ansatz).

Eine andere Möglichkeit ist es, Header-Dateien genau
einmal zu includen. Da es aber oft vorkommt, dass eine
bestimmte Header-Datei schon in meist mehreren anderen
includiert ist, hast Du keine andere Wahl als den
Makro-Ansatz.

Zu bemerken ist ausserdem, in fast allen
Header-Dateien der Standard-Bibliotheken genau so
verfahren wird (ausser vieleicht einigen MFC-generierten
Dateien, da bekommst Du aber auch Fehlermeldungen).

Gruss

Jörg

Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Gast

Jepp, glaube so habe ich das beschrieben.
Mit ging es aber um structs und typedefs -> die kann ich nicht in ein 
Header schreiben den ich mehrfach "include".

Jedenfalls nicht ohne diese Define-Struktur.

@ Andreas H.
static hat was mit der Gültigkeit der Variable zu tun,
sie ist sind ständig vorhanden aber nur von der dem entsprechenden 
Gültigkeitsbereich verfügbar.

static in einer Funktion lässte also die Variable "am Leben" ihr Wert 
wird in den erneuten Aufruf der Funktion gerettet.

Im gegensatz zu Automatischen Variablen, die werde bei jedem 
Funktionseintritt erneuet erstellt.

(wenn ich das richtig verstanden habe)

@ Jörg

Hmmm, Du hast mich überzeugt !
Jetzt werde ich das wohl oder übel benutzen müssen...

Aber irgendwie ist das ein bisschen merkwürdig !

Nur fürs verständnis :

Ich gehe mal davon aus das es gut ist jedes Headerfile in jedes andere 
und auch in main.c zu includieren.
(Das sollte doch Fehlerquellen die der Linker/Compiler nicht sieht 
erschlagen ?!?!)

Jedes Modul (also Header mit dem dazugehörigen Code) wird ja seperat 
übersetzt. Deshalb müssen die Strukturen die gemeinsam genutzt werden 
bekannt sein.

Unsere beiden "Makro-Kunstwerke" eleminieren den Includierten Code weg 
sobald er doppelt da wäre (>1 - mal includiert).

Wird dieses Your_Header_FileName durch den PräProzessor ersetzt ???

Bzw. Warum zweimal dieses : #ifndef bla

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grundsätzlich solltest Du nur das includieren was Du (bzw. das
entsrechende C/H-File) wirklich brauchst. Der Makro-Ansatz sorgt
dann dafür, dass jede Struktur/Klasse nur ein einziges mal
definiert wird.

Und ich muss Dich leider ein weiteres mal entäuschen:
_YourHeaderFileName_ muss von Dir jedes mal manuell durch z.B.
FileName oder ModuleName ersetzt werden.


Gruss

Jörg

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab ich fast vergessen: Was meinst Du mit

> Bzw. Warum zweimal dieses : #ifndef bla

#ifndef wird doch nur einmal verwendet

Gruss

Jörg

Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Du schriebst :

----
Eine einfache Möglichkeit (ähnlich Deiner) ist

    #ifndef YourHeaderFileName
    #ifndef YourHeaderFileName

am Anfang Deiner Header-Datei und

    #endif

am Ende der Header-Datei ( =: Makro-Ansatz).
----

Denke mal die zweite Zeile sollte mit #define beginnen.
Dann sieht es aber genauso wie bei meinem Beispiel aus ?!


Waren denn meine restlichen Ausführungen (Anfängertechnisch-)richtig ???


Das mit allen Headers includieren kommt bei meinem aktuellen projekt 
irgendwie fast zwangsläufig.
(rs232.h, timing.h, egt_map.h, defines.h, led.h, adc.h, eeprom.h -- 
Namen sind selbstredend)

Hab also mein main.c leergeräumt.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg wrote:
> Eine einfache Möglichkeit (ähnlich Deiner) ist
>
>     #ifndef __YourHeaderFileName__
>     #ifndef __YourHeaderFileName__
>
> am Anfang Deiner Header-Datei und
>
>     #endif
>
> am Ende der Header-Datei ( =: Makro-Ansatz).

Nix da, Namen, die einen oder mehrere Unterstriche vorangestellt 
bekommen, sind für den Compiler/Dessen Lib reserviert. Finger weg davon 
als normaler Codetipper.

Der gängige Standard ist:
#ifndef HEADERFILENAME_H_
#define HEADERFILENAME_H_
//...
#endif /* HEADERFILENAME_H_ */
oder
#ifndef HEADERFILENAME_H
#define HEADERFILENAME_H
//...
#endif /* HEADERFILENAME_H */

Wobei die Namen im Prinzip egal sind.#

Und ja, sowas ist durchaus üblich und gängig in der C/C++ Landschaft. 
Nennt sich Include-Guard: http://en.wikipedia.org/wiki/Include_guard.

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ frischling,

sorry, copy-and-paste-Fehler, muss natürlich #define statt zweitem
#ifndef heissen!!!


@ Simon K.,

ich weiss zwar, dass (glaube ich) alle compilereigene header-Dateien
mit doppelten Underscore ("__BLABLA..") anfangen, wusste aber nicht,
dass es sich um einen Standard handelt. Ist das eine
betriebssystemunabhängige Regel (ich arbeite fast nur unter Windows)?


Gruss

Jörg

Autor: Andreas H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Trotzdem...wann muss man einer Funktion ein "static" voranstellen?

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"static" bedeutet bei einer Funktion (oder einer globalen Variablen), 
dass nur in dieser "Compilation unit" d.h. .c-Datei darauf zugegriffen 
werden kann, ist also quasi das Gegenstück zu "extern".
Was bringt das? Der Compiler kann "static"-Funktionen z.B. inline'n und 
gar nicht als aufrufbare Funktion im Programm lassen (die klassischen 
*_putc-Funktionen sind da gute Beispiele - wenn in so einer Funktion nur 
ein I/O-Register geschrieben und anschließend gewartet wird).

hth. Jörg
ps. Das muss man gar nicht voranstellen ;)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg wrote:

> ich weiss zwar, dass (glaube ich) alle compilereigene header-Dateien
> mit doppelten Underscore ("__BLABLA..") anfangen, wusste aber nicht,
> dass es sich um einen Standard handelt. Ist das eine
> betriebssystemunabhängige Regel (ich arbeite fast nur unter Windows)?

Ja. Das ist im C-Standard so definiert.
Das es in C keine Namespaces gibt, wurd ein künstlicher 'Namespace'
eingerichtet, der besagt, dass alle Namen die mit zwei _ beginnen
oder einem _ gefolgt von einem Grossbuchstaben, für die
Systembibliothek reserviert sind.

Benutzte solche Namen einfach nicht und du wirst nie das Problem
haben, dass dir irgendein Systemheader in deine Variablen-Definitionen
hineinpfuscht.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas H. wrote:
> Trotzdem...wann muss man einer Funktion ein "static" voranstellen?

Wenn du haben willst, dass der Sichtbarkeitsbereich dieser
Funktion nur auf das *.c beschränkt bleibt, in dem diese Funktion
definiert ist.

Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#ifndef FILE
#define FILE

Code

#endif


^--- So müsste es doch auch Funktionieren ?!

FILE wird doch vom Präprozessor mit dem Dateinamen des gerade 
durchlaufenden Source/Modul ersetzt.

Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
 File  ohne leerzeichen sollte es heissen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
frischling wrote:

> FILE wird doch vom Präprozessor mit dem Dateinamen des gerade
> durchlaufenden Source/Modul ersetzt.

Aber nur im normalen C-Quelltext.
#ifndef, #define etc. sind Präprozessoranweisung. Die lässt der
Präprozessor in seiner Gesamtheit in Ruhe.
Irgendwo muss ja auch mal Schluss sein mit den Ersetzungen :-)

Autor: frischling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmmm, schade !
Rekursive Ersetzungen wären bestimmt auch sehr interessant...

Vielleicht sollte man das hier erlangte wissen in deinen Artikel mit 
aufnehmen. (kbuchegg)

Oder gibt es einen C-Kurs in dem sowas behandelt wird ?!

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
frischling wrote:
> Oder gibt es einen C-Kurs in dem sowas behandelt wird ?!

In jedem C-Buch würde ich sagen ;)

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@frischling:

scheinbar tappt jeder mal in die Falle zu glauben,
 __FILE__ 
ist in dem Fall der Filename der Header-Datei. Include fügt aber
nur die Headerdatei in das C-File ein und dann wird von
Präprozessor
 __FILE__ 
durch den Namen des C-Files (in dem includiert wird!) ersetzt.
Wünschenswert wäre ja mal ein Makro z.B. der Form
 __INCLUDEFILE__ 

mit dem Du den Headername automatisch generieren kannst, gibts aber
leider nicht.

Gruss

Jörg

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.