Hallo,
ich habe momentan eher eine Verständnisfrage als ein Problem, denn
funktionieren tut mein Code.
Ich habe einen unsigned 32 Bit Integer. Woher dieser kommt ist
nebensächlich. Zum Beispiel könnten die einzelnen Byte per USART
übertragen werden.
Interessant ist eher die Interpretation dieses Zahlenwertes: ich nehme
an es handelt sich um eine Adresse im Speicher und will sehen, was an
dieser Stelle steht.
Dazu soll eine Funktion einen Pointer liefern, der auf diese Adresse
zeigt.
Momentan schaut die Funktion so aus und funktioniert auch:
1
uint8_t *GetPointer(uint32_t addr)
2
{
3
uint8_t *ptr;
4
ptr = addr;
5
return ptr;
6
}
Benutzt wird sie zB so:
1
uint32_t addr_int = 0xFFFF1234;
2
uint8_t *addr_ptr = GetPointer(addr_int);
Wie gesagt, funken tuts so.
Mich interessiert aber die Warnung, die der Compiler in der Zeile "ptr =
addr;" ausgibt:
1
assignment makes pointer from integer without a cast
Ok, die Meldung ist noch verständlich. Füge ich einen Cast hinzu: "ptr =
(uint8_t *) addr;" gibt er diese Meldung aus:
1
cast to pointer from integer of different size
Hier versteh ichs nicht mehr.
Ich sage dem Compiler, er soll die Zahl, die er in "addr" findet, als
Adresse eines 8Bit Wertes interpretieren.
Wieso meckert er mir hier die Größe an? Die Größe eines Zeigers ist ja
vom Adressbus abhängig, nicht von der Größe des Wertes, auf den er
zeigt.
Beispiel: auf einer 16 Bit Maschine ist ein Zeiger auch dann 16Bit groß,
wenn er auf ein "unsigned long long" zeigt.
Es handelt sich dabei übrigens momentan um einen 8 Bit AVR.
Ich speichere die Adresse dennoch als 32 Bit Int um
a) kompatibel zu bleiben zu anderen Prozessoren
b) im Map File der erzeugten Binärdatei werden die Adressen auch als 32
Bit Wert angegeben. Das kommt wohl vom gcc, der eher für den PC Einsatz
gedacht ist und führt zu Spiegelbildern im Speicher, die aber nicht
stören.
Kann mir jemand erklären, wieso der Compiler meckert und wie ich casten
sollte, um die Warning zu beseitigen?
Nochmal, mir gehts hier primär ums "Warum?", denn funktionieren tut
alles...
Grüße,
Rudi
Rudi schrieb:> Ok, die Meldung ist noch verständlich. Füge ich einen Cast hinzu: "ptr => (uint8_t *) addr;" gibt er diese Meldung aus:>
1
> cast to pointer from integer of different size
2
>
Ein Pointer hat auf einem AVR-8-Bitter die Größe von 2 Bytes, Du
versuchst da aber, 4 Bytes (uint32_t) reinzuquetschen. Das heisst, 2
Bytes gehen verloren. Offenbar sind diese beiden aber immer 0 bei Dir,
deshalb scheint es dennoch zu funktionieren.
Stört sich der Compiler vielleicht daran, dass die Adresse ein 32bit
Wert ist, eigentlich aber nur 16bit sein dürfte (wie du oben ja schon
sagtest)?
Vielleicht mal die Adresse vor dem Pointer-Cast nach 16bit casten
probieren.
ptr = (uint8_t *) ( (uint16_t) addr );
Dachte nicht, dass der Compiler die Adressbusbreite des Targets so genau
nimmt. Im Mapfile schreibt er zB auch "0x00800310 var".
Anscheinend gingen aber genau die unnötigen 2 Bytes verloren.
Rudi schrieb:> Anscheinend gingen aber genau die unnötigen 2 Bytes verloren.
Ja, so ist es wohl. Fragt sich dann nur, warum Du einen uint32_t statt
uint16_t dafür verschwendest. Das bläht den AVR-Code nur unnötig auf.
Rudi schrieb:> Danke, die Idee war gut, so ist er zufrieden:
Die Idee war nicht gut. Denn damit ist deine
'zukünftige Kompatibilität' und damit der Grund, warum du überhaupt in
erster Linie einen uint32_t genommen hast, flöten gegangen.
D.h. als nächstes ist dieser uint32_t zu hinterfragen und der ganze
Klapperatismus zumindest (da es keine saubere Lösung gibt) mittels
Makros so zu verpacken, dass man ihn an geänderte Hardware durch das
Anpassen von ein paar Makros adaptieren kann.
>
1
> ptr = ((uint8_t *)((uint16_t)addr));
2
>
>> Dachte nicht, dass der Compiler die Adressbusbreite des Targets so genau> nimmt.
Wenn du versuchst mit einem Autobus in eine PKW-Garage zu fahren, bist
du heilfroh, wenn dich jemand davor warnt, dass da etwas schief gehen
kann und Teiles deines Autobusses möglicherweise diese Aktion nicht
überleben werden. Mit einem kleinen Autobus (mit 9 Sitzen) kommst du
gerade noch so rein. Mit einem städtischen Autobus (mit 50 Sitzen) aber
nicht mehr. Denn die sind meistens breiter.
Karl Heinz Buchegger schrieb:> Wenn du versuchst mit einem Autobus in eine PKW-Garage zu fahren, bist> du heilfroh, wenn dich jemand davor warnt, dass da etwas schief gehen> kann und Teiles deines Autobusses diese Aktion nicht überleben werden.
Karl Heinz, Deine Vergleiche sind immer herrlich!
Scheinbar "stirbt" nur die unnötige Blechverkleidung des Busses ;-)
Frank M. schrieb:> Karl Heinz Buchegger schrieb:>> Wenn du versuchst mit einem Autobus in eine PKW-Garage zu fahren, bist>> du heilfroh, wenn dich jemand davor warnt, dass da etwas schief gehen>> kann und Teiles deines Autobusses diese Aktion nicht überleben werden.>> Karl Heinz, Deine Vergleiche sind immer herrlich!>> Scheinbar "stirbt" nur die unnötige Blechverkleidung des Busses ;-)
Die Aussenspiegel würde ich jetzt nicht unbedingt als unnötig ansehen
:-)
Ist der Bus doppelt so breiten wie die Einfahrt dann hat man alles
andere als ein bißchen kosmetischen Schaden :-)
Danke Karl-Heinz, du hast natürlich Recht. Kompatibel bin ich momentan
mit dem gecaste nicht.
Frank M. schrieb:> Fragt sich dann nur, warum Du einen uint32_t statt> uint16_t dafür verschwendest.
Dazu muss ich weiter ausholen und dazusagen, dass ich eine Bibliothek
verwende die definierte Schnittstellen vorraussetzt.
Und die Schnittstelle um die es hier geht ist eben als 32 Bit Int
definiert.
Mir ist es deswegen überlassen, die geforderte Schnittstelle an die
verwendete Hardware anzupassen.
Rudi schrieb:> Und die Schnittstelle um die es hier geht ist eben als 32 Bit Int> definiert.
Dann unterscheide die Fälle einfach:
if (sizeof (ptr) == sizeof (uint16_t))
{
casten wie oben angegeben;
}
else
{
nicht casten;
}
Dann bleibt der Code kompatibel. Der Compiler wird den jeweiligen nicht
durchlaufenen Codeteil wegoptimieren.
Es gibt auch einen Integertypen, der immer groß genug ist um einen
Pointer zu speichern: uintptr_t. Das wäre wohl der richtige Typ für
deinen Parameter.
Rudi schrieb:> Im Mapfile schreibt er zB auch "0x00800310 var".
Das ist aber eher eine Krücke. Die ganze GNU-Toolchain kommt eigent-
lich schlecht bis gar nicht mit der beim AVR benutzten Harvard-
Architektur zurecht; die sind voll und ganz auf eine von-Neumann-
Architektur ausgerichtet, bei der alles an einem Adressbus hängt.
Um die Harvard-Busse des AVRs nun auf die von-Neumann-Idee der
Toolchain abzubilden, bekommen die einzelnen Busse Offsets. Der
SRAM-Bus hat dabei den Offset 0x800000, sodass alle im RAM liegenden
Werte nach dem Linken als oberhalb 0x800000 dargestellt werden.
(IO registers liegen im gleichen Adressraum, unterhalb des SRAM.)
Werte von 0 bis < 0x800000 beziehen sich entsprechend auf den Flash-
Adressraum.
Rudi schrieb:> Interessant ist eher die Interpretation dieses Zahlenwertes: ich nehme> an es handelt sich um eine Adresse im Speicher und will sehen, was an> dieser Stelle steht.
Der Vollständigkeit halber sei angemerkt, dass diese Annahme sehr
grenzwertig ist :-)
Zeiger sind keine Adressen. Du siehst ja hier schon, wie übel das durch
den Linker geht.
Eine eigene Frage?
Dieser Thread ist über 14 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.