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.