Forum: Compiler & IDEs uint32_t *


von _steff (Gast)


Lesenswert?

Servus!

Kann mir jemand sagen was die folgende Zeile auf sich hat?
#define CCNT ((uint32_t *)0x500004)    /* address of CCNT Register */

Warum steht das uint32_t dort wo es steht und wozu das *
?

Danke!

von Ulrich (Gast)


Lesenswert?

Ein * dereferenziert ein Objekt

von _steff (Gast)


Lesenswert?

Was bedeutet das genau?
Ist das wieder nur eine "vereinfachende" Schreibweise? Kann man das 
anders schreiben?

von Karl H. (kbuchegg)


Lesenswert?

Der * in diesem Zusammenhang ist ein 'Pointer'-Sternchen.

Sinn der Sache ist es einen Pointer zu konstruieren, der
auf eine bestimmte Speicherstelle zeigt.

Wenn du eine Variable erzeugst

int i;

oder auch

uint32_t j;

dann kümmert sich der Compiler darum, dass diese Variable
irgendwo im Speicher erzeugt wird. Du musst dich nicht
darum kümmern, wo dies konkret ist.

Nun gibt es aber Fälle, an denen du eine 'Variable' an eine
bestimmte Speicherstelle bugsieren möchtest. Stell dir einfach
vor, du hättest eine bestimmte Hardware, sagen wir mal eine
Uhr, die im Speicher an einer bestimmten Stelle auftaucht.
Dann wäre es doch schön, wenn man auf diese Uhr wie auf
jede andere Variable zugreifen könnte. Nur: Ich muss den
Compiler dazu bringen, eine bestimmte Speicheradresse
zu benutzen.

Nun: Eine Speicheradresse ist auch nur eine Zahl. Aber in
C hat jede Variable neben einer Speicheradresse auch noch
eine 2-te Information: den Datentyp der sich hinter dieser
Adresse versteckt.

  uin32_t j;

erzeugt eine Variable, der Compiler reserviert Speicher dafür
und kennt damit auch die Adresse an der j angelegt wird. Aber
er weiss noch mehr: Ihm wurde mitgeteilt, dass es sich um einen
uint32_t handelt. Also um einen Integer mit 32 Bit und dieser
Integer beinhaltet kein Vorzeichen.

Eine Speicheradresse ist auch nur eine Zahl. Schon: aber
umgekehrt gilt das nicht. Eine Zahl ist keine Speicher-
adresse. Denn dazu fehlt uns noch die Information was sich
denn an dieser Speicheradresse verbirgt.

Aber ich kann dem Compiler diese zusätzliche Information
beibringen. Ich kann eine Zahl zu einem Pointer casten,
indem ich dem Compiler sage, welcher Typ sich denn am
Ziel des Pointer verbirgt.

   (uint32_t *) 5

sagt dem Compiler:
  5                 nimm die 5
  * ) 5             und fasse diese 5 mal als Pointer auf
                    (also als Speicheradresse)
  (uint32_t *) 5    und zwar zeigt dieser Pointer auf einen
                    uint32_t

zusammengenommen ist das also die Information, dass sich
an der Speicheradresse 5 eine unsigned 32 Bit Zahl verbirgt.

Wenn ich die auslesen möchte, dann mache ich

   uint32_t j;
   j = * (uint32_t *)5;

Der erste * ist der 'Dereferenzier'-*, der zweite * ist
der Pointer-* der dafür sorgt, dass die 5 als Speicheradresse
aufgefasst werden.

Möchte ich an die Speicheradresse 5 einen uint32_t schreiben

  *(uint32_t *)5 = j;

Und damit der original-Autor nicht jedesmal diesen Rattenschwanz
schreiben muss, hat er sich dafür ein #define gemacht. Dies
hat dann auch den Vorteil, dass
  * die spezifische Zahl nur an einer Stelle vorkommt.
  * Im Programmtext anstelle der Zahl eine etwas aussage-
    kräftigere Bezeichnung verwendet werden kann

#define RTC  ( (uint32_t*)5 )

  j = *RTC;
  *RTC = j;

Sieht doch gleich viel besser aus.


von _steff (Gast)


Lesenswert?

Danke Karl!!
Ich habe das jetzt verstanden.

von _steff (Gast)


Lesenswert?

Was bedeutet eigentlich der parameter volatile in der Funktion?


#define write32(value,adress)

  *(volatile UINT32 *)adress = value


von Karl heinz B. (kbucheg)


Lesenswert?

volatile ist eine Attributierung eines Datentyps (ein
sog. Qualifizierer, so wie 'const').
Er sagt dem Compiler, dass sich eine Variable auch ausserhalb
des Kenntnisbereiches des Compilers verändern kann und der
Compiler daher aggresive Optimierungen mit dieser Variablen
unterlassen soll.

Worum gehts?
Es geht im weitesten Sinne immer um das hier:


   int i = 5;

   while( 1 ) {
     Ausgabe( i );
   }

Innerhalb der Schleife gibt es für i keine Möglichkeit
jemals verändert zu werden. Daher optimieren viele
Compiler das so, dass sie den Wert von i in einem CPU
internen Register zwischenspeichern und die Ausgabe
von diesem Register aus machen. Das spart Zeit, weil ja
kein Speicherzugriff gemacht werden muss um den Wert von
i zu erhalten.
Nur: Wenn sich hinter dem i in Wirklichkeit zb. eine Hardware-
schaltung verbirgt, dann gibt es sehr wohl eine Möglichkeit
wie i seinen Wert ändern kann. Nur ist das für den Compiler
nicht ersichtlich, wenn er an der Schleife arbeitet.

Das volatile teilt ihm dann mit: Spar die Optimierungen
des Zugriffs. Du musst immer an den Speicher ran, und kannst
den Wert nicht irgendwo zwischenspeichern.

von _steff (Gast)


Lesenswert?

Hallo nochmal,

Ich dachte ich habe es verstanden, jetzt sehe ich das Makro hier:

#define read32(adr)
  *(volatile UINT32 *)adr


Das Makro soll eine Adresse auslesen. Aber muss nicht irgendwo noch ein 
"="
stehen?

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


Lesenswert?

Nein, das schreibst du doch selbst hin:

myval = read32(someaddr);
      ^-- Hier

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ja, vor dem Aufruf des Makros:

  UINT32 bla;

  bla = read32(0xdeadface);

Machst Du einen manuellen Textersatz des Makros, ergibt sich

  bla = * (volatile UINT32 *) 0xdeadface;

Also wird der (von mir willkürlich vorgegebene) Wert 0xdeadface als 
Pointer auf UINT32 interpretiert (das macht der Ausdruck in der Klammer) 
und dann dereferenziert, sprich: der Wert bestimmt, der an der Adresse 
0xdeadface steht, was der Stern vor der Klammer erledigt.

Also steht in bla der Inhalt der Speicheradresse 0xdeadface

Das "volatile" weist den Compiler an, keinerlei Optimierungen betreffend 
den als Adresse angegebenen Wert durchzuführen.


Anmerkung: 0xdeadface ist auf vielen 32-Bit-Systemen keine gültige 
Adresse für UINT32-Zugriffe, da nicht ohne Rest durch 4 teilbar 
(misalignment). Auf x86-PCs geht das, aber beispielsweise auf ARMen 
nicht.

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.