Mit
for(unsigned i = 0; i<100;i++)
eeprom_write_byte((unsigned char*)i,0x22);
ist Ruhe.
Was dir der Compiler damit sagen wollte:
(unsigned char) hat 1 Byte, (unsigned char *) hat 2
und das ist zwar nicht falsch, aber könnte ein Hinweis auf ein
Missverständnis sein.
A. K. schrieb:> Was dir der Compiler damit sagen wollte:> (unsigned char) hat 1 Byte, (unsigned char *) hat 2> und das ist zwar nicht falsch, aber könnte ein Hinweis auf ein> Missverständnis sein.
Ich kann es jetzt nicht testen, aber die Warnung müsste auch kommen,
wenn für 'i' z.B. uint16_t (32, 64) verwendet wird. Das Entscheidende:
'i' ist eine normale Variable. Da die Funktion eine Adresse erwartet,
wird gemeckert. Einfach eine Zahl als Zeiger verwenden, kann ordentlich
in die Hose gehen. Denn: woher weißt du denn, dass an den Adressen 0..99
nichts steht? Hier vielleicht zufällig... Deshalb die Warnung. Typecast
lieber vermeiden!
Man könnte das so machen, dann gibt's (zumindest vom Compiler)
hoffentlich nichts zu meckern:
1
#define E_MAX 100
2
uint8_tEEMEMZiel[E_MAX];// Speicher im EPROM ordentlich reservieren
3
for(uint8_ti=0;i<E_MAX;i++)
4
eeprom_write_byte(&Ziel[i],0x22);
(Für dieses spezielle Problem gibt's natürlich 'eeprom_write_block')
Ralf schrieb:> Denn: woher weißt du denn, dass an den Adressen 0..99> nichts steht?
Grundsätzlich kann ich aber doch davon ausgehen, dass ich der einzige
bin, der dahin schreibt, oder?
D.h. Wenn ich nirgendwo eine Variable mit EEMEM deklariert habe, und
keine meiner libraries den EEPROM beschreibt, sollte ich mich beliebig
austoben dürfen. Richtig?
Oder optimiert der gcc soweit, dass er Sachen ins EEPROM auslagert?
Verwirrter Anfänger schrieb:> Grundsätzlich kann ich aber doch davon ausgehen, dass ich der einzige> bin, der dahin schreibt, oder?
Das ist schon richtig, aber nicht die feine Art! Der Compiler hat schon
seinen Grund, rumzumäkeln. Mit dem muss man sich nicht unbedingt
anlegen. Und wenn du hier schon, sagen wir mal, schlampig mit den
Datentypen umgehst, dann gibt's woanders mit Sicherheit böse
Überraschungen!
Ralf schrieb:> Ich kann es jetzt nicht testen, aber die Warnung müsste auch kommen,> wenn für 'i' z.B. uint16_t (32, 64) verwendet wird.
Ich hätte gedacht, der Wortlaut der Meldung des Compilers sei deutlich
genug. Bei unverträglichen Typen klingt das anders und ist auch keine
Warnung mehr, sondern ein Fehler.
> Das Entscheidende:> 'i' ist eine normale Variable. Da die Funktion eine Adresse erwartet,> wird gemeckert.
Drum hatte er dort ja auch den type cast verwendet. Mit dem wird der
type check ausgehebelt und pointer-integer Konvertierungen sind legal.
Hab' gerade mal meinen Bastelcomputer hochgefahren.
Und
Timo P. schrieb:> for(unsigned char i = 0; i<100;i++)> eeprom_write_byte((unsigned char*)i,0x22);
geändert zu
1
for(uint16_ti=0;i<100;i++)
2
eeprom_write_byte((uint8_t*)i,0x22);
... hätte nicht gedacht, dass der Compiler so eine Schlamperei
durchgehen lässt.
Ralf schrieb:> ... hätte nicht gedacht, dass der Compiler so eine Schlamperei> durchgehen lässt.
Das ist nicht die eleganteste Methode, EEPROM Speicher zu allozieren,
aber was die Sprache C angeht ist das vollkommen in Ordnung. Und muss
auch von jedem Compiler akzeptiert werden.
Wenn dir sowas schon gegen die Hutschnur geht, dann schau dir lieber
nicht an, was sich hinter Makros wie PORTC verbirgt. Bei deiner
Philosophie würde man bei Controller-Programmierung in Warnungen
regelrecht ersaufen.
Ich habe noch schnell mal so ein paar 'Konstruktionen' durchprobiert
(C++ Builder). Ich hätte gedacht, dass da wenigstens so ein klizekleines
Warnungchen kommen müsste. Aber richtig, es gibt ja immer mal wieder
spezielle Bibliotheksfunktionen, da werden nur 'int'-s übergeben und das
sind dann auch manchmal Adressen.
Aber trotzdem (ich hoffe es war nicht ernst gemeint):
Verwirrter Anfänger schrieb:> Wenn ich nirgendwo eine Variable mit EEMEM deklariert habe, und> keine meiner libraries den EEPROM beschreibt, sollte ich mich beliebig> austoben dürfen.
Ralf schrieb:> Aber trotzdem (ich hoffe es war nicht ernst gemeint):> Verwirrter Anfänger schrieb:>> Wenn ich nirgendwo eine Variable mit EEMEM deklariert habe, und>> keine meiner libraries den EEPROM beschreibt, sollte ich mich beliebig>> austoben dürfen.
Womit er Recht hat. Man kann das EEPOM auch als Bytestrom vergleichbar
zu einem Diskfile betrachten. Also keine einzelnen Variablen mit mehr
oder weniger fester Position. Habe ich auch schon gemacht. Dann sieht
das in der Implementierung ungefähr so aus wie hier.
A. K. schrieb:> Dann sieht das in der Implementierung ungefähr so aus wie hier.
Mmh, könnte ich mir vorstellen, aber irgendwo sollte schon mal
deklariert werden, dass vom EPROM was verwendet wird. Also ich meine,
nicht rumtoben.
A. K. schrieb:> Mit> for(unsigned i = 0; i<100;i++)> eeprom_write_byte((unsigned char*)i,0x22);> ist Ruhe.Ralf schrieb:> geändert zu> for(uint16_t i = 0; i<100;i++)> eeprom_write_byte((uint8_t*)i,0x22);
warum schreibt man nicht das hin, was man meint:
willibald schrieb:> Was hier addr heißt, ist in Wahrheit kein Zeiger, sondern ein Offset.
nein, es ist ein Zeiger in den eeprom-Adressbereich, der auch mit 0
anfängt.
willibald schrieb:> Dieser Sachverhalt sollte sich im API widerspiegeln:> void eeprom_write_byte (uint16_t addr, uint8_t value);> wäre daher meiner Meinung nach besser.
wenn schon, dann
void eeprom_write_byte (uint16_t offset, uint8_t value);
willibald schrieb:> Meiner Meinung nach ist das API falsch gewählt:void eeprom_write_byte (uint8_t> *addr, uint8_t value);> Was hier addr heißt, ist in Wahrheit kein Zeiger, sondern ein Offset.
Offset zu was? Es ist die Adresse einer Speicherstelle, also das, was
eben auch in einem Zeiger steht.
> Dieser Sachverhalt sollte sich im API widerspiegeln:void eeprom_write_byte
(uint16_t addr, uint8_t value);
> wäre daher meiner Meinung nach besser.
Wenn man dann eine EEMEM-Variable definiert, müßte man deren Adresse
immer erst in einen Integer konvertieren, um sie an die Funktion zu
übergeben.
Vlad Tepesch schrieb:> nein, es ist ein Zeiger in den eeprom-Adressbereich, der auch mit 0> anfängt.
Zeigertypen sind dann sinnvoll, wenn es etwas gibt, was man damit
dereferenzieren kann. Das ist hier nicht der Fall, darum wäre es besser,
den Adress-Offset als Integer anzugeben.
Mir fällt auch keine sinnvolle Anwendung ein, die an dieser Stelle
tatsächlich einen Pointer braucht. Wisst ihr eine? Alle Szenarien, die
mir einfallen, führen entweder auf definierte Offsets oder auf
Pointer-Differenzen (also auch wieder Ganzzahlen).
willibald schrieb:> Zeigertypen sind dann sinnvoll, wenn es etwas gibt, was man damit> dereferenzieren kann. Das ist hier nicht der Fall, darum wäre es besser,> den Adress-Offset als Integer anzugeben.
Im Flash auch? Das ist in GCC ebensowenig dereferenzierbar. Die Leute
würden sich über die vielen dann notwendigen Casts sicherlich wenig
freuen. Und beides verschieden zu definieren wäre grotesk.
> Wisst ihr eine?
Ganz normale EEPROM Variablen.
willibald schrieb:> Mir fällt auch keine sinnvolle Anwendung ein, die an dieser Stelle> tatsächlich einen Pointer braucht. Wisst ihr eine?
Siehe http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM> Alle Szenarien, die mir einfallen, führen entweder auf definierte Offsets oder
auf
> Pointer-Differenzen (also auch wieder Ganzzahlen).
Nochmals: Differenzen zu was?
OK, dieser EEMEM-Ansatz war mir nicht bekannt. Liegt vermutlich daran,
dass ich kein AVR-Anwender bin.
Aber ihr habt Recht, das Konzept ist stimmig. Wieder was gelernt.
Ralf schrieb:> ... hätte nicht gedacht, dass der Compiler so eine Schlamperei> durchgehen lässt.
Was erwartest du?
Mit dem Cast sagst du dem Compiler explizit: Halt die Klappe.