Hallo!
Tut mir leid - ich bin gerade zu faul, das zu deduzieren:
Ist eine Compile-Zeit Konstante der Form "&variable" auf Systemen mit
16-bit Zeigern im Normalfall auch schon vor ihrer Verwendung immer
maximal 16-bit lang? Also im Falle von
1
void* p = &da;
ist klar, dass p ein Pointer mit der im System üblichen Länge ist. Es
geht mir um das "&da", z.B. in
1
struct LargeStruct {
2
char vieleBytes[65535];
3
int hier;
4
} *eeprom = (struct LargeStruct*)0;
5
6
uint32_t addr = (uint32_t) &eeprom->hier;
Es existieren wohl Header-Files die sowas für AVRs machen und ich frage
mich, ob das eine GNUe Extension ist oder nicht. Immerhin hat der
Ausdruck "&eeprom->hier" ja eigentlich schon den Typ "int*" - und der
ist 16-bit breit...
Heiko L. schrieb:> Ist eine Compile-Zeit Konstante der Form "&variable" auf Systemen mit> 16-bit Zeigern im Normalfall auch schon vor ihrer Verwendung immer> maximal 16-bit lang?
Auf Systemen mit 16-bit-Pointern haben Adressen 16 bit, ja sicher.
> geht mir um das "&da", z.B. instruct LargeStruct {> char vieleBytes[65535];> int hier;> } *eeprom = (struct LargeStruct*)0;
Diese Struktur hat (mindestens, je nach int-Breite) 65537 Bytes und kann
somit nicht mehr mit 16-bit-Pointern beackert werden.
> uint32_t addr = (uint32_t) &eeprom->hier;
Dafür nimmt man besser nicht uint32_t, sondern uintptr_t.
> Es existieren wohl Header-Files die sowas für AVRs machen
Weil das eine Harvard-Architektur ist und man deswegen nicht einfach
Daten im Programmflash haben kann, daher auch das progmem-Gefrickel. Das
hat aber nichts mit 8 bit zu tun.
Nop schrieb:> Diese Struktur hat (mindestens, je nach int-Breite) 65537 Bytes und kann> somit nicht mehr mit 16-bit-Pointern beackert werden.
Wo mir gerade einfällt, dass das gerade noch ginge: Es muss natürlich
heißen
Es gibt gebankte Systeme und es gibt Systeme mit unterschiedlichen
Pointerlängen z.B RAM und ROM.
Und es gibt C-Compiler, die für spezielle Controller den Standard weit
biegen, oder ihn gar nicht reklamieren. Ohne Stack (als Beispiel) sind
rekursive Funktionen (direkt, oder indirekt über Funktionspointer) hält
nicht möglich.
Es gibt gebankte Systeme und es gibt Systeme mit unterschiedlichen
Pointerlängen z.B RAM und ROM.
Und es gibt C-Compiler, die für spezielle Controller den Standard weit
biegen, oder ihn gar nicht reklamieren. Ohne Stack (als Beispiel) sind
rekursive Funktionen (direkt, oder indirekt über Funktionspointer) hält
nur eingeschränkt möglich.
Heiko L. schrieb:> Tut mir leid - ich bin gerade zu faul, das zu deduzieren:> Ist eine Compile-Zeit Konstante der Form "&variable" auf Systemen mit> 16-bit Zeigern im Normalfall auch schon vor ihrer Verwendung immer> maximal 16-bit lang?
Ich verstehe den Sinn der Frage nicht. Ein Pointer in C ist ein Pointer
ist ein Pointer. Wenn du einen Pointer in einer Variable speichern
willst, muß die Variable vom entsprechenden (Pointer)Typ sein. Das wars
schon. Mehr mußt du nicht wissen. Insbesondere ist vollkommen egal,
wieviel Bits so eine Pointervariable hat. Zumindest so lange du dich auf
die legalen Operationen mit Pointern beschränkst. Das wären im
wesentlichen Vergleich, Dereferenzierung und Inkrement/Dekrement.
>
1
> struct LargeStruct {
2
> char vieleBytes[65535];
3
> int hier;
4
> } *eeprom = (struct LargeStruct*)0;
5
>
6
> uint32_t addr = (uint32_t) &eeprom->hier;
7
>
>> Es existieren wohl Header-Files die sowas für AVRs machen
Die was machen?
> und ich frage mich, ob das eine GNUe Extension ist oder nicht.
Ob was eine GNU Extension ist?
> Immerhin hat der> Ausdruck "&eeprom->hier" ja eigentlich schon den Typ "int*"
Wieso "eigentlich"? Das ist ein Pointer auf int. Die Konvertierung zu
einem uint32_t ist formal falsch. Was dabei passiert, ist
implementation defined, also mindestens schon mal nicht portabel.
Möglicherweise tut es auch gar nicht das, was man erwartet. Und ich kann
auch nicht erkennen, welchen Sinn der Cast haben soll.
Zur allgemeinen Verwirrung: Wie steht es dabei um die Worte near und
far? Sollte man die nicht berücksichtigen? Welches Speichermodell ist
gewählt, SMAL, HUGE, ...?
Frage über Fragen ... ;)))
Axel S. schrieb:>Die Konvertierung zu einem uint32_t ist formal falsch.>Was dabei passiert, ist implementation defined, also mindestens schon mal >nicht
portabel.
Ich schnalle jetzt nicht ganz, wieso injektive Abbildungen nicht
portabel sein sollen? Die Frage ist, ob die Menge der möglichen Urbilder
&x der Abbildung (uint32_t)&x bei C-Compilern für 16-bit-pointer Systeme
a-priori die Mächtigkeit 65536 hat.
linker Linker schrieb:> Zur allgemeinen Verwirrung: Wie steht es dabei um die Worte near und> far? Sollte man die nicht berücksichtigen? Welches Speichermodell ist> gewählt, SMAL, HUGE, ...?>> Frage über Fragen ... ;)))
Endlich mal etwas vernünftiges....!
gcc zB kennt gar kein "far", soweit ich las?
Heiko L. schrieb:> Immerhin hat der> Ausdruck "&eeprom->hier" ja eigentlich schon den Typ "int*" - und der> ist 16-bit breit...
... und noch mehr Verwirrung:
Geht es jetzt um den Wert, auf den der Zeiger zeigt?
int sind mind. 16 Bit
oder geht es um den Zeiger selbst, also um die Adresse?
struct ... &(eeprom->hier), der könnte u. a. auch 12 oder 14 Bit
haben.
;)))
Heiko L. schrieb:> Axel S. schrieb:>> Die Konvertierung zu einem uint32_t ist formal falsch.>> Was dabei passiert, ist implementation defined, also mindestens>> schon mal nicht portabel.> Ich schnalle jetzt nicht ganz, wieso injektive Abbildungen nicht> portabel sein sollen?
Du mußt jetzt ganz tapfer sein. Die Sprache C garantiert keine injektive
Abbildung von Pointern auf Integer. Sie garantiert noch nicht mal, daß
ein Integer den "Wert" eines Pointers überhaupt repräsentieren kann [1]
Ein C-Compiler könnte bei der Zuweisung eines Pointers an einen Integer
den letzteren einfach immer auf 0 setzen und wäre immer noch
standardkonform. Das ist genau das, was implementation defined
bedeutet. Ein Pointer in C ist ein Pointer ist ein Pointer ist kein
Integer.
Wenn du mit Adressen statt Pointern arbeiten willst und wenn du du
Addressen gern mit Zahlen in einen Topf wirfst, dann programmiere
Assembler. Aber laß die Finger von C.
[1]
https://wiki.sei.cmu.edu/confluence/display/c/INT36-C.+Converting+a+pointer+to+integer+or+integer+to+pointer
insbesondere: "Any pointer type may be converted to an integer type.
Except as previously specified, the result is implementation-defined. If
the result cannot be represented in the integer type, the behavior is
undefined. The result need not_ be in the range of values of _any
integer type." (Hervorhebung von mir)
Axel S. schrieb:> The result need not_ be in the range of values of _any> integer type." (Hervorhebung von mir)
Allerdings, C99 zur Rettung, aus demselben Artikel:
"Any valid pointer to void can be converted to intptr_t or uintptr_t and
back with no change in value."
Deswegen sagte ich oben ja schon, nimmt man für sowas uintptr_t und
nicht uint32_t.
Axel S. schrieb:> Wenn du mit Adressen statt Pointern arbeiten willst und wenn du> Addressen gern mit Zahlen in einen Topf wirfst, dann programmiere> Assembler. Aber laß die Finger von C
Oder mach es so :-)
8051:
sbit LED = P0^4;
LED ^= 1;
ARM:
volatile unsigned char *P0 = (unsigned char *) 0xA0000000;
#define LED (*(P0+4))
LED ^= 1;
Nop schrieb:> Axel S. schrieb:>>> The result need not_ be in the range of values of _any>> integer type." (Hervorhebung von mir)>> Allerdings, C99 zur Rettung, aus demselben Artikel:>> "Any valid pointer to void can be converted to intptr_t or uintptr_t and> back with no change in value.">> Deswegen sagte ich oben ja schon, nimmt man für sowas uintptr_t und> nicht uint32_t.
Bleibt immer noch die Frage: Wozu? Du kannst den Pointer also zu einem
(formal) Integer-Typ konvertieren und wieder zurück. Aber sobald du
iegendwas mit der Integer-Repräsentation anstellst, sind alle Garantien
futsch. Dann hättest du das Dingen aber auch gleich in einer Pointer-
Variable belassen können.
Ist ein bißchen wie das Spielgeld in Itchy-und-Scratchy-Land [1].
Richtiges Geld kann gegen Spielgeld getauscht werden und wieder zurück.
Aber sonst nimmt keiner das Spielgeld in Zahlung.
[1] aus "Die Simpsons"
Axel S. schrieb:> Dann hättest du das Dingen aber auch gleich in einer Pointer-> Variable belassen können.
"Palim Palim, eine Flasche Pommes bitte". ;)
(Dieter Hallervorden)
Axel S. schrieb:> Bleibt immer noch die Frage: Wozu? Du kannst den Pointer also zu einem> (formal) Integer-Typ konvertieren und wieder zurück. Aber sobald du> iegendwas mit der Integer-Repräsentation anstellst, sind alle Garantien> futsch.
Das braucht man typischerweise für Lowlevel-Code, der ohnehin nicht
portabel ist. Man kann auch damit herumrechnen und das dann wieder in
einen Pointer umwandeln, BTDT. Allerdings muß man sich dann selber drum
kümmern, daß dann Sachen wie gültige Adreßbereiche und Alignment
eingehalten werden.
Es ist ansonsten aber auch vollkommen normal, Integerzahlen zu Adressen
zu casten. Die Registerdefinitionen auf Cortex-M in den Headerfiles tun
genau das, und da das defines sind, ist das reine Textersetzung.
Man kann das auch dazu gebrauchen, ganze Speicherbereiche am Linker
vorbei zu verwalten. Nützlich ist das etwa fürs Backup-RAM beim
Cortex-M4, welches man nämlich auch verriegeln kann. Das muß man bei
Schreibzugriffen dann aber erstmal entriegeln und danach wieder
verriegeln, und davon weiß der Linker nichts.
Axel S. schrieb:> Bleibt immer noch die Frage: Wozu?
Wieso? Dass da in deinem Kopf Sachen wie das Zeug hin- und hercasten,
damit rumrechnen und dann wieder als normale Zeiger benutzen
herumschwirrt, hat doch keinerlei Auswirkung auf die Mächtigkeit der
Urbildmenge, oder doch?