Hallo zusammen, ich möchte für ein Projekt eine Header-Datei mit ca 50 EEprom-Adressen anlegen. Gibt es eine Möglichkeit das mit dem Präprozessor zu machen? Ich weiß net, wie ich den zum Rechnen bewegen soll
Micha R. wrote: > ich möchte für ein Projekt eine Header-Datei mit ca 50 EEprom-Adressen > anlegen. Was könnte der Fragesteller damit bloß gemeint haben ??? In einer Headerdatei wird nichts angelegt und Adressen schonmal garnicht. Anlegen kann man nur Funktionen und Variablen, das macht man in einem Object (C-Source). Ein Objekt kann dann der Linker an eine bestimmte Adresse linken, wenn man es wünscht. Sonst legt er es an, wo Platz ist. Peter
Nein Peter, so mein ich es nicht. In der Datei soll nur sowas stehen, wie:
1 | #define adresse1 0x0000
|
2 | #define adresse2 0x0002
|
3 | #define abc 0x00010
|
Ich wollte allerdings die Adressen zur Kompilierzeit automatisch erstellen lassen, so, dass ich ohne Probleme die Speichergröße ändern, bzw. neue Werte einfügen kann.
@micha prinzipiell ist das kein thema. man muß sich nur vor augen halten das der präprozessor NUR eine REINE textersetzung macht. das eigentliche rechnen übernimmt der compiler zum eigentlichen compilierzeitpunkt. du kannst dir die adressen folgendermaßen generieren lassen : const (char *) Data EEPROM [] = {"data 1", "data 2", "data 3"}; #define ADDR1 ( (char *) & (Data [0]) ) #define ADDR2 ( (char *) & (Data [1]) ) #define ADDR3 ( (char *) & (Data [2]) ) so würdest du dir für jeden eintrag ein Makro-generieren. Willst du diese Makro-generierung automatisch machen bedarf es noch etwas mehr. du müsstest dann (mittels geeigneter Makros) dir die Daten sowie die Adresse automatisch Erzeugen lassen. Beispiel : Du machst eine Datei in dem deine zu generierende Daten als Tabellen organisiert sind : DATA_START DATA_ENTRY (ENTRY_1, "data 1") DATA_ENTRY (ENTRY_2, "data 2") DATA_ENTRY (ENTRY_3, "data 3") DATA_END diese datei speicherst du unter (z.b.) "data_cfg.h" in deiner Headerdatei die aus dieser Tabelle enums und die Adressen generiert machst du folgendes : enum { #define DATA_START #define DATA_ENTRY(name,data) name, #define DATA_END #include "data_cfg.h" #undef DATA_START #undef DATA_ENTRY #undef DATA_END }; das erzeugt dir enums für deine array-einträge (das erlaubt dir namensmässig auf die einträge des arrays zuzugreifen. mit : #define DATA_START #define DATA_ENTRY(name,data) const (char *) Ptr_##name = (char *) (& Data [name] ); #define DATA_END #include "data_cfg.h" #undef DATA_START #undef DATA_ENTRY #undef DATA_END erzeugst du dir für jeden array eintrag eine zeiger konstante. der name der konstanten fängt immer mit Ptr_ an. also wird mit damit folgendes erzeugt : Ptr_ENTRY_1 (zeiger auf "data 1") Ptr_ENTRY_2 (zeiger auf "data 2") Ptr_ENTRY_3 (zeiger auf "data 3") und zu guter letzt erzeugst du mit const (char *) Data [] EEPROM = { #define DATA_START #define DATA_ENTRY(name,data) data, #define DATA_END #include "data_cfg.h" #undef DATA_START #undef DATA_ENTRY #undef DATA_END }; in deinem c file das eigentliche Datenarray. ich weiß zwar nicht ob diese beschreibung dir weiterhilft bzw. ob es zu deinem problem passt, aber ich arbeite recht exzessiv mit dem präprozessor, und damit habe ich schon einige konstruukte realisiert die das Programmieren und die erweiterbarkeit/wartbarkeit erheblich vereinfacht haben. wenn es nicht zu dem passt was du suchst, sag doch mal genau was du brauchst dann kann ich dir vielleicht einen besseren ansatz geben. gruß rene
Schon wieder jemand, der dem Präprozessor wundersame Fähigkeiten zuschreibt. Wo lernt man das? Das Stichwort heisst hier "struct". Die EEPROM-Daten in eine solche hineinpacken und fertig.
Mir gings drum, nicht für jede Adresse Speicherplatz zu verbraten.
Micha R. wrote:
> Mir gings drum, nicht für jede Adresse Speicherplatz zu verbraten.
Das tust Du erst, wenn Du auch einen Pointer anlegst.
Structs und Enums verbraten erstmal garnichts.
Wenn Du eine Konstante als Pointer castest und auf dessen Inhalt
zugreifst, wird die Adresse nicht als Variable angelegt.
Peter
da gibts noch folgende möglichkeit (etwas dirty, sollte aber funktionieren): du missbrauchst ein enum für "zeiger" : enum { #define DATA_START #define DATA_ENTRY(name,data) Ptr_##name = ((int) ((char *) &(Data [name]))), #define DATA_END #include "data_cfg.h" #undef DATA_START #undef DATA_ENTRY #undef DATA_END }; setzt vorraus das intern die enums denselben zahlenbereich haben wie zeiger. du baust dir damit folgendes zusammen enum { Ptr_ENTRY_1 = ((int) ((char *) & (Data [ENTRY_1))), Ptr_ENTRY_2 = ((int) ((char *) & (Data [ENTRY_2))), Ptr_ENTRY_3 = ((int) ((char *) & (Data [ENTRY_3))), }; enums brauchen kein speicherplatz auf dem controller. und sofern die maximale interne datenbreite für enums mindestens genausogroß ist wie deine zeigerbreite (z.b. 16 bit) funktioniert das wunderbar. gruß rene
TheMason wrote: > ich arbeite recht exzessiv mit dem > präprozessor, und damit habe ich schon einige konstruukte realisiert die > das Programmieren und die erweiterbarkeit/wartbarkeit erheblich > vereinfacht haben. Ja, Deinen Programmierstil erkennt man unter tausenden sofort heraus. Ob sowas aber als noch wartbar empfunden wird, ist Ansichtssache. Ich hab mich mit enums noch nie anfreunden können. Peter
>Ob sowas aber als noch wartbar empfunden wird, ist Ansichtssache. ok ist etwas gewöhnungsbedürftig, aber gerade bei vielen einträgen und verschachtelten daten (z.b. array von zeiger auf structs die ihrerseits wieder zeiger auf daten bzw structs enthalten) nimmt die wartbarkeit meines programmierstils wieder zu. (z.b. Menüsteuerung mit Menüeinträgen in mehreren Sprachen) das ganze lohnt sich erst ab einer gewissen komplexität bzw. anzahl von daten bei denen man sich schnell durch copy&paste die finger bricht. obwohl es auch ganz schön ist eine konfiguration (z.b. Port-pins eines angeschlossenen LCD's) einfach in eine kleine konfigurationsdatei zu legen und dann auf jedem prozessor verwenden zu können, und bei änderung (HW/Platform) nur die Konfigurationsdatei anpassen zu müssen. >Ja, Deinen Programmierstil erkennt man unter tausenden sofort heraus. bin halt einfach nur ein fleißig fauler programmierer der nutzen/aufwand des mehrtippens wieder raus haben will :-) (sonst würde ich alles nur hard-coded programmieren und magic numbers nur so sprießen) :-)) falls interesse besteht kann ich ja mal aus meinem programmierstil einen artikel machen (der dann genauso wenig besucht wird wie mein Parser bzw. mein audio-projekt *mecker mecker :-)) mal schauen gruß rene
struct EEPOM_Daten { int a; double b; char c[10]; }; Benötigt keinen Platz, legt aber die relativen Adressen fest. An diese Offsets kommst du mit dem quasi-standard Makro offsetof() ran. Gibt's den nicht schon, dann beispielsweise definieren mit: #define offsetof(s,m) ((char *)&((s*)0)->m-(char*)0) und benutzen wie offsetof(EEPROM_Daten,b) Meist benutzt man das EEPROM jedoch für Parameter, die dann sowieso als live-Kopie im RAM liegen. Da kann man die dann auch gleich in dieser struct drin lassen und ohne offsetof en bloc hin und her kopieren. @TheMason: enum zur Speicherung von Adressen. Autsch, das tut weh.
@andreas
>enum zur Speicherung von Adressen. Autsch, das tut weh.
ich sag doch : nicht sauber aber funktioniert. aber mal im ernst : wenn
ein enum 16 bit umfasst und letztenendes NUR einen wert darstellt und
ein zeiger ebenfalls dasselbe darstellt (rein zahlenmässig) was spricht
dann dagegen ?
doch nur die interne implementierung eines enums die dann vom compiler
"falsch" interpretiert werden kann, oder ?
16 bit sind 16 bit.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.