Ich habe schon wieder ein Problem damit wie Headerdateien dynamisch
verwendet werden sollten.
Angenommen ich habe eine Headerdatei header1.h. Diese ist projektbezogen
und enhält generelle Definitionen, die keinen speziellen Peripherien
zugeordnet werden können.
In dieser definiere ich zB
1
#ifndef DEF_H
2
#define DEF_H
3
#define ON GPIO_PIN_SET
4
#define OFF GPIO_PIN_RESET
5
#define NONE 0xFFFFFFFF
6
#endif
Jetzt habe ich zB eine c-Datei datei1.c und eine h-Datei datei1.h davon.
Jetzt habe ich zB in der c-Datei eine Funktion, die zB als Parameter OFF
benötigt. Sie wird zB auch in der datei2.c in einer beliebigen Funktion
ebenfalls als Parameter benötigt und sonst nirgends.
Jetzt muss ich in die jeweiligen Headerdateien datei1.h und datei2.h die
header1.h einbinden.
Jetzt habe ich folgendes Problem.
Wenn nun datei1.c und datei2.h irgendwo als Vorlage dient und ich ein
komplett anderes Programm schreibe, aber diese c-Datei benötige, muss
ich doch ständig die projektbezogene Headerdatei mitziehen, obwohl diese
mit dem neuen Programm nichts zu tun hat.
Denke ich da zu kompliziert?
Hi Jens,
datei1 ist universell (also das Paar aus .c und .h), während header1.h
projektbezogen ist? Wenn ja, dann ist das die falsche Reihenfolge des
inkludierens bzw. der Abhängigkeiten. Du möchtest Deine
projektspezifischen Dateien von allgemeinen abhängig halten, nicht
umgekehrt.
Was Du tun kannst:
Gib das ON und OFF als Parameter an Deine universellen Code-Teile - oder
allgemeiner, gib alles projektspezifische hinein (Parametrisierung).
Gruß, jois3
Eine anderer Ansatz (der mir persönlich nicht gefällt) ist, solche
Definitionen ins Build Script (bzw. Makefile) zu schreiben und dem
Compiler als Parameter "-D" mit zu geben. Diese Definitionen sind dann
im gesamten Projekt verfügbar ohne irgend eine Datei zu inkludieren.
Ein Klassiker, wo das üblich ist: "-DF_CPU=16000000"
Stefanus F. schrieb:> Eine anderer Ansatz (der mir persönlich nicht gefällt) ist, solche> Definitionen ins Build Script (bzw. Makefile) zu schreiben und dem> Compiler als Parameter "-D" mit zu geben. Diese Definitionen sind dann> im gesamten Projekt verfügbar ohne irgend eine Datei zu inkludieren.>> Ein Klassiker, wo das üblich ist: "-DF_CPU=16000000"
Das muss ich mir mal anschauen, auch wenn ich es vermutlich nicht
brauchen werde. Es einfach zu wissen, schadet ja nie.
jois3 schrieb:> Hi Jens,>> datei1 ist universell (also das Paar aus .c und .h), während header1.h> projektbezogen ist? Wenn ja, dann ist das die falsche Reihenfolge des> inkludierens bzw. der Abhängigkeiten. Du möchtest Deine> projektspezifischen Dateien von allgemeinen abhängig halten, nicht> umgekehrt.>> Was Du tun kannst:> Gib das ON und OFF als Parameter an Deine universellen Code-Teile - oder> allgemeiner, gib alles projektspezifische hinein (Parametrisierung).>> Gruß, jois3
Also das heisst, dass ich die folgende Definition
1
#ifndef DEF_H
2
#define DEF_H
3
#define ON GPIO_PIN_SET
4
#define OFF GPIO_PIN_RESET
5
#define NONE 0xFFFFFFFF
6
#endif
in der datei1.h und datei2.h einfügen muss.
Dann existiert in der header.h die Definition einfach nicht, wenn sie
sonst auch im Projekt nirgends benötigt wird. Richtig?
Hi Jens,
> Also das heisst, dass ich die folgende Definition
[...]
> in der datei1.h und datei2.h einfügen muss.> Dann existiert in der header.h die Definition einfach nicht, wenn sie> sonst auch im Projekt nirgends benötigt wird. Richtig?
Naja, eine nicht-existierende Definition führt freundlichstenfalls zu
einer aussagekräftigen Fehlermeldung des Compilers...
Ist jetzt natürlich ohne konkreten Quelltext ziemlich abstrakt, aber
mein Vorschlag zielt eher in Richtung ganz expliziter Parameterübergabe.
Also sprich, Du hast im projektspezifischen Code z.B. eine Prozedur
namens "SetRedLEDOn", die dann eine "SetGPIO" im allgemeinen Teil
aufruft, und dabei die Konstanten (die in projektspezifischen Teilen
definiert sind) als Aufrufparameter übergeben. Während SetRedLEDOn dann
z.B. SetGPIO(ON) aufruft, kann eine SetRedLEDOff dann eben SetGPIO(OFF)
aufrufen. Ist etwas mehr Quelltext, dafür hat's sprechende Namen und
eine feste Schicht, an der fachliches (Rote LED schalten) in technisches
(GPIO-Wert setzen) übergeht.
Gruß, jois3
Jens schrieb:> Jetzt muss ich in die jeweiligen Headerdateien datei1.c und datei1.h die> header1.h einbinden.
Ja. Wenn du Definitionen aus header1.h benötigst, dann mußt du header1.h
#includen.
> Jetzt habe ich folgendes Problem.> Wenn nun datei1.c und datei1.h irgendwo als Vorlage dient und ich ein> komplett anderes Programm schreibe, aber diese c-Datei benötige, muss> ich doch ständig die projektbezogene Headerdatei (header1.h) mitziehen,
Ja.
> obwohl diese mit dem neuen Programm nichts zu tun hat.
Nein. Wenn datei1.c oder datei1.h irgendwelche Definitionen aus
header1.h benötigen, dann haben sie offensichtlich etwas damit zu tun.
Deswegen kann header1.h nicht als "nicht dazu gehörig" betrachtet
werden.
Ich glaube dein Fehler passiert viel eher:
Jens schrieb:> Angenommen ich habe eine Headerdatei header1.h. Diese ist projektbezogen> und enhält generelle Definitionen
"projektbezogen" und "generell" beißt sich. Es kann doch eigentlich nur
entweder das eine oder das andere sein. Trenne diese beiden. Allgemeine
Definitionen wirst du mehr oder weniger immer mitziehen müssen,
projektbezogene Definitionen aber höchstwahrscheinlich nie.
Unabhängig von deiner konkreten Frage komme ich nicht umhin zu bemerken,
daß du für meinen Geschmack viel zu viel versuchst, durch Makros
wegzukapseln oder zu abstrahieren. Indirektion ist ein nützliches
Hilfsmittel. Aber zuviel davon kann die Übersichtlichkeit des Codes auch
wieder verschlimmern.
Immer dann, wenn du Makros in andere Makros verpackst, solltest du dich
fragen, ob das sinnvoll ist. Immer dann, wenn du ein Makro nur an einer
einzigen Stelle im Code verwendest, dito. Dein früheres Makro mit clock
enable fällt genau in diese Kategorie. Typischerweise macht man das
genau einmal im Programm und packt dann diesen Code auch in eine passend
benannte Funktion wie z.B. hardware_init(void). Diese Funktion ist ganz
klar projektspezifisch und es reicht vollkommen, wenn du da drin die
Clocks der diversen Peripherieinheiten anschaltest; vielleicht jeweils
noch mit einem Kommentar, warum.