warning: cast to pointer from integer of different size

OP #2243952
Lesenswert?

Hallo!


Folgender Minimalcode liefert die Warning. Warum, weiß ich nicht. Ich 
habe extra einen typecast gemacht.

1
#include <avr/io.h>
2
#include <avr/eeprom.h>
3

4
int main()
5

6
{
7
  for(unsigned char i = 0; i<100;i++)
8
    eeprom_write_byte((unsigned char*)i,0x22);
9

10
  return 0;
11
}

Danke für Erklärungen!
Gast #2244199
Lesenswert?

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_t EEMEM Ziel[E_MAX];     // Speicher im EPROM ordentlich reservieren
3
for (uint8_t i=0; i < E_MAX; i++)
4
 eeprom_write_byte(&Ziel[i],0x22);
(Für dieses spezielle Problem gibt's natürlich 'eeprom_write_block')
Gast #2244207
Lesenswert?

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?
Gast #2244214
Lesenswert?

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!
#2244222
Lesenswert?

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.
Gast #2244270
Lesenswert?

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_t i = 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.
#2244276
Lesenswert?

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.
Gast #2244287
Lesenswert?

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.
#2244293
Lesenswert?

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.
Gast #2244741
Lesenswert?

Meiner Meinung nach ist das API falsch gewählt:
1
void eeprom_write_byte (uint8_t *addr, uint8_t value);
Was hier addr heißt, ist in Wahrheit kein Zeiger, sondern ein Offset. 
Dieser Sachverhalt sollte sich im API widerspiegeln:
1
void eeprom_write_byte (uint16_t addr, uint8_t value);
wäre daher meiner Meinung nach besser.
#2245031
Lesenswert?

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);
Gast #2245078
Lesenswert?

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.
Gast #2245133
Lesenswert?

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).
#2245135
Lesenswert?

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.
Gast #2245153
Lesenswert?

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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren