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
voidmain(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
voidmain(void)
18
{
19
...
20
}
Gibt's da irgendwelche bedenken?
Kann es zu Problemen kommen?
Vielen Dank
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.
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?
> 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.
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 ;-)
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
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)
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.
#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.
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.
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
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!
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.
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 ^^
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.
>> 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.
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
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.
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.