Forum: Compiler & IDEs Cast eines Int zu Pointer


von Rudi (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Dominik S. (dasd)


Lesenswert?

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 );

von Rudi (Gast)


Lesenswert?

Danke, die Idee war gut, so ist er zufrieden:
1
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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Rudi (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von stdint.h (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

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
Noch kein Account? Hier anmelden.