Forum: PC-Programmierung eine allgemeine Header für alle Prototypen


von Cimbom G. (cimbomgs)


Lesenswert?

Hi,

arbeite gerade an einem riesen Projekt, wo ich viele Funktionen habe.
Ich programmiere in C und wie man weiß, braucht man für jede Funktion 
einen Prototyp.

Aber zu jeder Funktion gehört auch eine Quell-Code-Datei (*.c) und ein 
Header-Datei (*.h)..

Wie jeder Vernünftige es machen würde, beginnt auch bei mir jede 
Header-Datei mit:
1
#ifndef _BSP_H
2
#define _BSP_H
3
4
...
5
6
#endif

so jetzt zu meiner eigentlichen Frage :-)
ich wollte eine "Allgemeine Header-Datei" erstellen, in dem alle 
Header-Dateien inludiert werden, die erzeugt wurden.

Somit bräuchte ich nicht immer alle Headers includieren, ich müsste nur 
die "Allgemeine Header-Datei" einmal unclidieren.

ungefähr so...

...anstatt:
1
//Datei test.c
2
#include "a.h"
3
#include "b.h"
4
#include "c.h"
5
#include "d.h"
6
#include "e.h"
7
#include "f.h"
8
...
9
void main(void)
10
{
11
...
12
}

...will ich:
1
//Datei allgemein.h
2
#ifndef _ALLGEMEIN_H
3
#define _ALLGEMEIN_H
4
5
#include "a.h"
6
#include "b.h"
7
#include "c.h"
8
#include "d.h"
9
#include "e.h"
10
#include "f.h"
11
...
12
13
14
//Datei test.c
15
#include "allgemein.h"
16
17
void main(void)
18
{
19
...
20
}

Gibt's da irgendwelche bedenken?
Kann es zu Problemen kommen?

Vielen Dank

von yalu (Gast)


Lesenswert?

Nein, wenn es zwischen den Einzelheaders keine Konflikte (bspw. durch
mehrfach definierte Makros) gibt.

Die Kompilierzeiten werden (je nach Größer der Headers) etwas länger
sein, weil der Compiler auch unbenutzte Headers unnötigerweise
durchnudelt.

von Cimbom G. (cimbomgs)


Lesenswert?

yalu wrote:
> Nein, wenn es zwischen den Einzelheaders keine Konflikte (bspw. durch
> mehrfach definierte Makros) gibt.

durch
#ifndef abc
#define abc
ist doch sichergestellt, dass es zu keinem Konflikt kommt

> Die Kompilierzeiten werden (je nach Größer der Headers) etwas länger
> sein, weil der Compiler auch unbenutzte Headers unnötigerweise
> durchnudelt.

ja gut das passiert ja nur einmal beim Beginn, es muss ja nur einmal 
kompiliert werden..

Hat es irgendwelche Auswirkungen auf den Speicher?

von yalu (Gast)


Lesenswert?

> durch
> #ifndef abc
> #define abc
> ist doch sichergestellt, dass es zu keinem Konflikt kommt

Ja, wenn alles richtig untereinander koordiniert ist, gibt es keine
Probleme. Ich meinte auch eher so etwas von der Sorte:

temperatursensor.h:
#define UMRECHNUNGSFAKTOR 13

drucksensor.h
#define UMRECHNUNGSFAKTOR 472

Normalerweise wird temperatursensor.h nur in temperatursensor.c und
drucksensor.h nur in drucksensor.c includet. Wenn du beide gemeinsam
includest, gibt es einen Konflikt. Ein zusätzliches #ifdef löst zwar
den Konflikt auf, dafür wird dann aber für beide Sensoren der gleiche
Umrechnungsfaktor benutzt. Da helfen nur unterschiedliche Namen, was
sowieso der bessere Stil ist, also bspw. TEMP_UMRECHNUNGSFAKTOR und
DRUCK_UMRECHNUNGSFAKTOR.

> Hat es irgendwelche Auswirkungen auf den Speicher?

Nicht dann, wenn du dich an die Gutestilregel hältst, dass in
Headerfiles nur Deklarationen aber keine Definitionen von Variablen
oder Funktionen stehen. Reine Deklarationen belegen keinen Speicher,
da kannst du soviel unnötiges Zeugs includen wie du lustig bist.

von Cimbom G. (cimbomgs)


Lesenswert?

yalu wrote:
> Ich meinte auch eher so etwas von der Sorte:
> temperatursensor.h:
> #define UMRECHNUNGSFAKTOR 13
> drucksensor.h
> #define UMRECHNUNGSFAKTOR 472
> Ein zusätzliches #ifdef löst zwar den Konflikt auf

überall wo ein #define steht, wird bei mir vorher ein #ifndef realisiert
#ifndef UMRECHNUNGSFAKTOR
#define UMRECHNUNGSFAKTOR 13
#endif

>TEMP_UMRECHNUNGSFAKTOR und
> DRUCK_UMRECHNUNGSFAKTOR.

ganz genau so wird's auch gemacht. Keine gleiche Bezeichnungen für 
Konstanten :-)


@yalu
Danke für deine Hilfe ;-)

von Cimbom G. (cimbomgs)


Lesenswert?

hmmm.. wieso ist die Reihenfolge der Includes so wichtig?

naja ich hatte die Reihenfolge der Includes nicht beachtet gehabt und 
habe gesehen, dass mein Programm nicht gelaufen ist.
Jetzt wo die Reihenfolge stimmt, funktioniert das Programme und bekomme 
keine Fehlermeldungen

von Simon K. (simon) Benutzerseite


Lesenswert?

Cimbom Gs wrote:
> überall wo ein #define steht, wird bei mir vorher ein #ifndef realisiert
> #ifndef UMRECHNUNGSFAKTOR
> #define UMRECHNUNGSFAKTOR 13
> #endif

Das ist auch mist. Wenn eine doppelte Definition auftritt (siehe Post 
von yalu) Dann merkst du dies nicht. Problematisch ist aber, wenn du in 
Tempsensor.c alle h-Dateien inkludierst und den eigentlich 
Temp-Umrechnungsfaktor heraus-ge-ifndef-nt hast und der jetzig gültig 
der Umrechenfaktor der Temperatur ist.

(In deinem Falle würde also immer das zuletzt definierte gelten)

von Cimbom G. (cimbomgs)


Lesenswert?

Simon K. wrote:
> (In deinem Falle würde also immer das zuletzt definierte gelten)

stimmt, da hast du ganz recht. Es ist das selbe wie wenn ich die #ifndef 
weglasse. Aber ich verwende solche Definitionen nicht, zumindest nicht 
mehrere die gleiche Bezeichnung haben.

von Chris (Gast)


Lesenswert?

#ifndef _BSP_H
#define _BSP_H

Das obige ist uebrigens nicht erlaubt, weil Bezeichner mit fuehrendem _ 
fuer den Compiler reserviert sind. Lass den Unterstrich am besten 
einfach weg, um wohlgeformten Code zu schreiben. Oder mach ihn ans Ende, 
da ist es erlaubt.

void main() ist ein anderer Punkt, das sollte selbstverstaendlich int 
main() heissen, damit jeder C-Compiler das akzeptiert.

von Cimbom G. (cimbomgs)


Lesenswert?

Chris wrote:
> Das obige ist uebrigens nicht erlaubt, weil Bezeichner mit fuehrendem _
> fuer den Compiler reserviert sind.

das höre ich zum ersten mal :-(..Bei Minus-Zeichen "-" würde ich sagen 
ok geht nicht aber dass Unterstrich für Compiler reserviert sein soll, 
noch nie gehört.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> aber dass Unterstrich für Compiler reserviert sein soll,
> noch nie gehört.

Ist aber so, sofern der Unterstrich ein führender ist.

von Cimbom G. (cimbomgs)


Lesenswert?

Rufus t. Firefly wrote:
>> aber dass Unterstrich für Compiler reserviert sein soll,
>> noch nie gehört.
>
> Ist aber so, sofern der Unterstrich ein führender ist.

wenn das so ist, warum beginnt jede Header-Datei in der Library von 
Freescale mit:
#ifndef __xxx
#define __xxx
bei 2 Unterstrichen würde sich ja wohl nichts ändern..

Es ist wohl von Compiler zu Compiler unterschiedlich und bei dem 
Compiler, was ich benutze, gilt der Unterstrich nicht

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es gibt einen -verbindlichen- C-Standard, wenn sich ein Hersteller nicht 
daran hält, gilt der Standard dennoch.

von Cimbom G. (cimbomgs)


Lesenswert?

Rufus t. Firefly wrote:
> Es gibt einen -verbindlichen- C-Standard, wenn sich ein Hersteller nicht
> daran hält, gilt der Standard dennoch.

Was kann denn passieren, wenn der Standard nicht eingehalten wird?

Ich kann es nirgends finden, dass führender Unterstricht nicht erlaubt 
sei..kann mir jemand einen Link geben?

Danke!

von Karl H. (kbuchegg)


Lesenswert?

Cimbom Gs wrote:
> Rufus t. Firefly wrote:
>> Es gibt einen -verbindlichen- C-Standard, wenn sich ein Hersteller nicht
>> daran hält, gilt der Standard dennoch.
>
> Was kann denn passieren, wenn der Standard nicht eingehalten wird?

Du kannst gleichartige Definements in vom Hersteller zur Verfügung
gestellten Header Files und deinen eigenen haben. Solche Fehler
sind äußerst ekelig und schwer zu finden.

Durch die Regelung hat man so etwas wie einen Namespace geschaffen,
so dass garantiert ist (wenn sich alle daran halten), dass es
zu keinen unliebsamen Überraschungen kommen kann.

>
> Ich kann es nirgends finden, dass führender Unterstricht nicht erlaubt
> sei..kann mir jemand einen Link geben?

Kauf dir den C-Standard. Da stehst drinnen.

Mein Gott: Das ist doch keine Reketentechnik! Halte dich an die
einfache Regel, dass ein Name der mit Unterstrich und dann ein
Grossbuchstabe für dich tabu ist und gut ists. Das ist doch nun
wirklich kein Beinbruch.


http://gcc.gnu.org/onlinedocs/cpp/System_002dspecific-Predefined-Macros.html

> wenn das so ist, warum beginnt jede Header-Datei in der Library von
> Freescale mit:
> #ifndef __xxx
> #define __xxx
> bei 2 Unterstrichen würde sich ja wohl nichts ändern..

Freescale ist meines Wissens immer noch Hersteller eines Compilers.
Damit gilt für Freescale genau diese Regelung: Ihre eigenen
definements machen sie mit __ und damit in dem 'Namespace' der
für den Compilerhersteller reserviert wurde.

von Cimbom G. (cimbomgs)


Lesenswert?

OK jetzt verstehe ich :-)

>All names which begin with two underscores, or an underscore and a capital 
>letter, are reserved for the compiler and library to use as they wish

Daher sollte ich als Entwickler KEINE Unterstriche benutzen ^^, weil es 
ja für den Compiler und der Library reserviert ist.
Und darum beginnt in der Library vom Hersteller jede Header-Datei mit 2 
Unterstrichen
> #ifndef __xxx
> #define __xxx

und daher gilt diese Aussage:
>Du kannst gleichartige Definements in vom Hersteller zur Verfügung
>gestellten Header Files und deinen eigenen haben.

Vielen Dank @all und besondern @ Karl heinz Buchegger..

Dankeschön ^^

von Oliver Sch. (Gast)


Lesenswert?

Sorry ich finden Vorschlag Müll ehrlich,

Es macht keinen Sinn erst alle Funktionen in eigne Header und C-Files zu 
kapseln und dann alles über einen Generischen Header wieder zu 
inkludieren, Dann kannst du dir das Kapseln auch gleich Sparen. Zumal 
das nicht nur beim Kompielerin mehr Zeit Kostet und unter Umständen 
großer Objekt Dateien erzeugt. Auch das Warten wird ein Horror.
Kapsel deine Funktion Vernünftig , so das es nicht zu so vielen includes 
kommt, wenn dir das nicht möglich ist stehe zu Komplexität deines 
Projekt. Aber alle inkludiert in einen Header auslagern macht kein Sinn. 
Zumal du dann auch Probleme mit defines bekommen Könntest
Und das

#ifndef BLA
#define BLA 25
#endif

ist auch keine Lösung wenn du bla 2 mal hast bekommst du falsche 
Ergebnisse.
wenn es zu viele Headers gibt, die du immer wieder inkludieren musst 
hast du entweder ein sehr Komplexes Projekt oder eine falsche Aufteilung 
der Funktionalität in die Header, beides löst man durch ein Überdenken 
des Software Design.

von Rolf Magnus (Gast)


Lesenswert?

>> Die Kompilierzeiten werden (je nach Größer der Headers) etwas länger
>> sein, weil der Compiler auch unbenutzte Headers unnötigerweise
>> durchnudelt.
>
> ja gut das passiert ja nur einmal beim Beginn, es muss ja nur einmal
> kompiliert werden..

... pro Datei, die deinen generischen Header verwendet.

von Cimbom G. (cimbomgs)


Lesenswert?

ja gut aber das macht ja die Software..sobald daraus ein Hex-Datei 
erstellt wird und auf den Mikrocontroller geflasht wird, spielt es doch 
keine Rolle mehr oder?!

Es verbraucht auch nicht mehr Speicherplatz

von Bartli (Gast)


Lesenswert?

Ahem, ich arbeite seit kurzem an einem Projekt mit, welches zwar nicht 
allzu kaputt ist, aber:
Es gibt in dem Projekt ziemlich viele magische Header, die von fast 
jeder Quelldatei direkt oder indirekt eingebunden werden, und - das ist 
das Üble - bei Erweiterungen der Software geändert werden müssen. Je 
nachdem an was du gerade genau arbeitest, machst du dann relativ viele 
Kaffee- und Rauchpausen, bis du wieder mal testen kannst.

Wenn dein Projekt wirklich "riesig" ist, wie du in deinem ersten Post 
schreibst, würd ich an deiner Stelle Dateiabhängigkeiten nicht 
auswuchern lassen.

von Bartli (Gast)


Lesenswert?

Insbesondere würd ich Dateiabhängigkeiten nicht durch Einführung eines 
generischen Headers künstlich vergrössern.

von Karl H. (kbuchegg)


Lesenswert?

Cimbom Gs wrote:
> ja gut aber das macht ja die Software..sobald daraus ein Hex-Datei
> erstellt wird und auf den Mikrocontroller geflasht wird, spielt es doch
> keine Rolle mehr oder?!
>
> Es verbraucht auch nicht mehr Speicherplatz

Das nicht.

Aber du führst damit das Arbeitsprinzip deines Make
ad absurdum.

Make hat die Aufgabe Abhängigkeiten beim Erstellen eines
Projektes zu berücksichtigen. Wenn ein Source Code File
B.CPP nicht von einem Header File A.H abhängt, dann braucht
es auch nicht neu kompiliert werden, wenn sich A.H ändert.

Mit einem generellen Header File hängt dann aber jedes *.CPP
von allen Headern *.H ab. D.h. jede Änderung in irgendeinem
x-beliebigen Header File führt dazu, dass alle *.CPP neu
kompiliert werden.

Bei kleinen Mikrocontroller Projekten mag das angehen.
Bei großen Projekten (vor allem, wenn wir uns von µC
entfernen und auf PC-Ebene übergehen) kann das aber
zeitlich ins Gewicht fallen und einen ziemlichen
Unterschied in der Entwicklungszeit ausmachen. Entwicklungs-
zeit ist aber teuer.

Das andere Argument:
Wenn du tatsächlich alle Header Files quer durch das Projekt
in vielen (bis allen) *.CPP Files benötigst, dann sollte man
mal untersuchen, ob hier nicht ein Designfehler vorliegt. Die
einzige Ausnahme ist die Datei in der main() enthalten ist, aber
ansonsten ist dieser Fall eher selten.
Mit der einfachen Grundregel "jedes Header File, jedes Source Code
File inkludiert genau die Header die es selbst unbedingt benötigt"
fährt man eigentlich auf lange Sicht immer am Besten.

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.