www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Pointer ist 3 Byte große?


Autor: Stefan S. (stefanst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich habe ein merkwürdiges Problem: Ich möchte gerne die Adresse eines 
Pointers (vom Pointer selbst) in einzelnen Bytes Speichern. Da das nicht 
auf anhieb funktioniert hat (das Zerlegen des Pointers), habe ich mal 
folgendes ausprobiert:
sizeof(char*);

Das liefert mir zu meinem Erstaunen den Wert 3!! Warum das denn? Ich 
nutze den An2131 von Cypress mit einem 8051-Kern. Das müsste doch 
eigentlich 2 zurückliefern, oder?

Viele Grüße,
Stefan

Autor: Schneemann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin zwar kein C-ler, aber könnte es sein, das die Function SizeOf() 
die string-beendende #0 mitzählt?

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pointer mit einem "string-beendenden #0", sehr, sehr interessant!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für Maschinen mit getrennten Adressräumen existieren Compiler, die mit 
Pointern alle Adressen ansprechen können. Realisiert wird das, indem zur 
Adresse noch eine Adressraumkennung hinzugefügt und der Zugriff per 
Laufzeitfunktion abgewickelt wird. Das könnte hier der Fall sein. 
Möglicherweise ist dann per Option wählbar, ob das für alle Pointer 
gilt, oder nur für solcherart gekennzeichnete.

Autor: rgf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
C war und ist schon immer krank! ;)

Autor: H.J.Seifert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Insbesondere beim 8051 ist das erforderlich, da es 
Adressüberschneidungen gibt. Der Pointer muss also ein Angabe enthalten, 
für welchen Speicher er gilt (data, idata, xdata, code), zumindest gilt 
das für den generic-Pointer.
Das 1.Byte des pointers stellt also den Typ dar, danach kommen 2 
Adress-Bytes. Kann allerdings bei anderen Compilern auch anders sein:-).

Wenn du den Speichertyp schon bei Deklaration angibst, hat er auch nur 2 
Byte, kann dann allerdings wirklich nur für diesen Speichertyp verwendet 
werden.

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha. Ein typisierter Pointer. Toll. Damit kann man das auf's RAM, auf's 
EEPROM und auf's Flash los ?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist Abhängig von der Implementierung.

Ein Zeiger darf auch 1, 2, 4, 5, 6, 7, ... Bytes breit sein. Ein Zeiger 
muss noch nicht mal eine Zahl sein, er kann auch eine Struktur o.ä. 
sein.

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das müsste doch eigentlich 2 zurückliefern, oder ?

Nein.
Auch beim C166 sind's 3, bei manchen Mainframes auch 6.

Vermutlich ist der Cypress-Kompiler so flexibel,
dass er Zeiger in Code und Zeichen in (externes) RAM
unterschieden kann und braucht dafür 1 bit mehr als 16.

Manchmal kann man daran mit Compileroptionen drehen,
aber man sollte sich über die Konseqeunzen im klaren
sein, wenn Pointer nicht mehr unterschiedbar sind.

Autor: Andreas R. (rebirama)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jup ein Pointer mit Typisierung, geht für alles, erzeugt mehr Code und 
ist langsamer.
schau mal ins Manual deines Compilers, da sollte es drin stehen.

Ich kenns von sdcc:
generische pointer, wie in deinem fall haben 3 byte.
spezialisierte pointer, z.B. für xram haben nur 2 byte.
theoretisch könnte ein pointer für den data-,idata- oder pdata- bereich 
auch nur 8bit haben, ob das der sdcc kann, weiß ich allerdings gerade 
nicht.

Wie auch immer, wenn du spezielle pointer verwenden willst, muss du dir 
gedanken um dein memory-model machen und dein code muss auf das verdauen 
spezieller pointer ausgelegt sein.

Autor: Stefan S. (stefanst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey!
Danke erstmal für die vielen Antworten, jetzt ist mir die Sache auch 
klar geworden :D
Was ich aber komisch finde: Kann es sein, dass der 8051 eine Adresse 
"falsch herum" abspeichert? Wenn var0 an Adresse 0D60 sitzt und ich 
folgendes mache
var5 = (unsigned char) (&var0);
var6 = (unsigned char) (((int)(&var0))>>8);
var7 = (unsigned char) (((int)(&var0))>>16);
liefert mir das als Resultat

var5 = 60
var6 = 0D
var7 = 0

Gut, hier fällt mir schonmal auf, dass die 1, die dem Pointer auf Grund 
der Lage im XDATA-Bereich haben müsste, nicht enthalten ist...

Mache ich nun folgendes:
xdata long test _at_ 0x0D70;
test = &var0;
und lese nacheinander die Speicherzellen 0x0D70, 0x0D71, 0x0D72 aus (vom 
PC), so liefert mir das für
0x0D70: 0
0x0D71: 01
0x0D72: 0D
0x0D73: 60

Kann mir das jemand erläutern?

Viele Grüße,
Stefan

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan S. schrieb:

> var7 = (unsigned char) (((int)(&var0))>>16);

Wird immer 0 sein, weil "int" nur 16 Bits hat. Besser:

var7 = (unsigned char) (((long)(&var0))>>16);

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan S. schrieb:
> Was ich aber komisch finde: Kann es sein, dass der 8051 eine Adresse
> "falsch herum" abspeichert?

Bei nem 8-Bitter gibt es kein "falsch herum". Egal, wie es der Compiler 
macht, es sind immer 2 Bytezugriffe erforderlich.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas R. schrieb:
> Wie auch immer, wenn du spezielle pointer verwenden willst, muss du dir
> gedanken um dein memory-model machen

Nö, das Memory Model gibt nur an, wo default Variablen abgelegt werden.

Deshalb sollte man das Large-Modell nur dann nehmen, wenn man wirklich 
triftige Gründe dafür hat. Default Variablen werden dann nämlich sehr 
langsam und erzeugen sehr viel Code.

In jedem Memory-Model kann man alle Memory-Specifier verwenden.
Pointer ohne Specifier sind immer 3 Byte groß (generic Pointer).


Peter

Autor: Stefan S. (stefanst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Stefan S. schrieb:
>
>> var7 = (unsigned char) (((int)(&var0))>>16);
>
> Wird immer 0 sein, weil "int" nur 16 Bits hat. Besser:
>
> var7 = (unsigned char) (((long)(&var0))>>16);

Okay, das macht Sinn ;-) habs mal mit "long" statt "int" versucht, jetzt 
ist die 1 wieder da!

Nach dem, was ich im Netz gefunden habe, scheint der AN2131 mit dem 
8051-Kern also nach Big-Endian-Format sortiert...

Danke!

Viele Grüße,
Stefan

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ...  nach Big-Endian-Format sortiert...

Intel µCs haben immer little-endian.

Motorola, Renesas (H8) big-endian und SH sind meist umschaltbar.
Ist das nicht schön? :-)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast schrieb:

> Intel µCs haben immer little-endian.

Das ist hier nicht relevant, da der 8051 alle Pointer jenseits des 256 
Byte Primär-RAMs über DPTR nutzt. Daher kann der Programmierer das 
halten wie er will.

In diesem Fall könnte eine Rolle spielen, dass die Laufzeitfunktionen 
zuallererst auf das Tag-Byte zugreifen müssen, dies also sinnvollerweise 
an der ersten Stelle steht.

> Motorola, Renesas (H8) big-endian und SH sind meist umschaltbar.
> Ist das nicht schön? :-)

Noch schöner war NS32000. Big-endian bei Konstanten im Code und 
little-endian sonst. DEC hatte auch welche verbrochen, bei denen die 
Bytereihenfolge im Wort und die Wortreihenfolge im Doppelwort 
unterschiedlich war

Autor: anonymous (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der AN2131 ist nicht zwingend in einem festen Format sortiert. Die 
endianess der Variablen im Speicher bestimmt der Compiler.

Keil macht für den 8051 big endian.
sdcc little endian.

Genauso machen das die Hardwaredesigner mit den Peripheriemodulen,
dort können 16bit Register wiederum in beliebiger Reihefolge liegen.
hab mal das Datenblatt des AN2131 überflogen(den ich noch die verwendet 
habe).
Im USB-Teil sind einige 16bit register etc big-endian, andere wiederum 
little-endian.
Solange du auf die Register immer schön mittels der Namen der 
Einzelbytes zugreifst und sie von Hand "zusammenshiftest" ist alles in 
Butter.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die endianess der Variablen im Speicher bestimmt der Compiler.

Nee, nee. Bei 8-Bittern kann er das machen, aber sobald ein 16- oder 
32-Bitter eine int oder long-Variable speichert, legt die CPU (oder 
sogar das Businterface) die Anordnung fest.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast schrieb:

> Nee, nee. Bei 8-Bittern kann er das machen, aber sobald ein 16- oder
> 32-Bitter eine int oder long-Variable speichert, legt die CPU (oder
> sogar das Businterface) die Anordnung fest.

Klar doch, aber hier geht es eben um 8051, da legt die Maschine nichts 
fest und der Compiler hat die Wahl.

Auch bei vielen 8-Bit Prozessoren wird das durch 16-Bit Adressen im 
Speicher ebenfalls von der Maschine fest- oder nahegelegt, aber eben 
nicht bei 8051.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.