Forum: Mikrocontroller und Digitale Elektronik &-operator auf 8-bit Controllern


von Heiko L. (zer0)


Lesenswert?

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...

von Nop (Gast)


Lesenswert?

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.

von Heiko L. (zer0)


Lesenswert?

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
1
struct LargeStruct {
2
  char vieleBytes[65536]; // !
3
  ...

von A. S. (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von linker Linker (Gast)


Lesenswert?

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

von Heiko L. (zer0)


Lesenswert?

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.

von Heiko L. (zer0)


Lesenswert?

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?

von Nop (Gast)


Lesenswert?

Heiko L. schrieb:

> gcc zB kennt gar kein "far", soweit ich las?

Das wird angelehnt an C99 als far_t bezeichnet. ;-)

von linker Linker (Gast)


Lesenswert?

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.

;)))

von Axel S. (a-za-z0-9)


Lesenswert?

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)

von Nop (Gast)


Lesenswert?

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.

von Lothar (Gast)


Lesenswert?

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;

von Axel S. (a-za-z0-9)


Lesenswert?

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"

von Teo D. (teoderix)


Lesenswert?

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)

von Nop (Gast)


Lesenswert?

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.

von Heiko L. (zer0)


Lesenswert?

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?

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.