mikrocontroller.net

Forum: Compiler & IDEs uint32_t *


Autor: _steff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein * dereferenziert ein Objekt

Autor: _steff (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: _steff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Karl!!
Ich habe das jetzt verstanden.

Autor: _steff (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was bedeutet eigentlich der parameter volatile in der Funktion?


#define write32(value,adress)

  *(volatile UINT32 *)adress = value


Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: _steff (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, das schreibst du doch selbst hin:

myval = read32(someaddr);
      ^-- Hier

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

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.