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:
1
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
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.
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.
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.
> 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.
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.
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
1
var5=(unsignedchar)(&var0);
2
var6=(unsignedchar)(((int)(&var0))>>8);
3
var7=(unsignedchar)(((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:
1
xdatalongtest_at_0x0D70;
2
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
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);
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
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
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
> ... 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? :-)
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
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.
>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.
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.