Hallo, folgende Code-Zeile aus der stm32f10x.h versuche ich nun schon seit längerem zu verstehen, komme aber einfach nicht dahinter was hier passiert: #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) vllt kann mir jemand Schritt für Schritt erklären, was hier genau passiert bzw. gemacht wird. Ich möchte mir die uC Programmierung selber beibringen und komme auch jeden Tag einen Schritt weiter, jedoch gibt es immer wieder Hürden, die mir das Leben schwer machen :( Vielen Dank für Eure Hilfe Gruss Alex
Guten Morgen, Define ist hier ein Text Ersatz, Das heißt was links steht GPIOA wird mit dem Text rechts ersetzt.
Gpio Base ist eine Zahl die die Adresse der Peripherie enthält. Die wird in einen Zeiger auf die Peripherie gecastet. Das define ersetzt gpioa durch den Teil rechts, so dass man es als Verwender schöner schreiben kann
Karl schrieb: > Gpio Base ist eine Zahl die die Adresse der Peripherie enthält. Die wird > in einen Zeiger auf die Peripherie gecastet. Guten Morgen und vielen Dank euch Beiden. genau, das #define ersetzt den text durch den Präprozessor. Was links steht, wird durch das was rechts steht, ersetzt. Das eigentliche Kopfzerbrechen macht mir dieser "Cast". GPIO_Base Wenn ich in dem Headerfile die Spur von GPIO_Base zurückverfolge,finde ich, dass das eine Integerzahl ist: #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE ((uint32_t)0x40000000) was genau macht dieser Cast am Ende ? ((GPIO_TypeDef *) GPIOA_BASE) GPIO_TypeDef ist ja eine Benutzerdef.-Datentyp, eine Struct: typedef struct { __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; } GPIO_TypeDef; Wie wird hier diese GPIOA_BASE mit dem (GPIO_TypeDef *) umgewandelt ? Was kann ich nach diesem Cast mit GPIOA_BASE machen ?
Die Adresse GPIOA_BASE wird auf einen Pointer vom Typ GPIO_TypeDef gecastet. Der Preprozessor ersetzt GPIOA_BASE also durch ((GPIO_TypeDef *) GPIOA_BASE). Damit kannst du einfach über GPIOA_BASE->x auf die Registerinhalte von GPIOA zugreifen. Wenn es das nicht gäbe müsstest du jedesmal ((GPIO_TypeDef *) GPIOA_BASE)->x schreiben.
Alex schrieb: > Wie wird hier diese GPIOA_BASE mit dem (GPIO_TypeDef *) umgewandelt ? Die Peripherie ist in den Speicher gemappt an einer bestimmten Adresse. Startend ab dieser Adresse gibt es Register, die in dem Struct definiert sind, um sie zu steuern. Jetzt möchte man quasi das Struct mit der Adresse startend bei der Adresse der Peripherie haben, damit man leichter auf die Register zugreifen kann. Daher castet man einen Pointer auf die Basis-Adresse der Peripherie zu einem Struct-Pointer und voila. Jeder Zugriff auf das Struct landet dann bei der richtigen Peripherie.
Das bedeutet, wann immer Du
1 | GPIOA
|
schreibst, bekommt der Compiler
1 | ((GPIO_TypeDef *) ((((uint32_t)0x40000000) + 0x10000) + 0x0800)) |
vorgesetzt. Das bekommt man raus, wenn man alle Textersetzungen durch die Defines ineinander einsetzt. Viele Compiler kennen auch eine Kommandozeilenoption, um das Ergebnis der Präcompilerbemühungen als Datei abzuspeichern. Wenn man jetzt mal selber diese Konstanten aufaddiert, bleibt von diesem Ausdruck
1 | ((GPIO_TypeDef *) 0x40010800) |
übrig. Also ein Zeiger auf eine Struktur vom Typ GPIO_TypeDef, die auf Adresse 0x40010800 zeigt. Verwendet wird das Ding in dem man
1 | GPIOA->ODR=42UL; |
schreibt. Das Dereferenziert den Zeiger und wählt das Element ODR der Struktur.
N. M. schrieb: > Der Preprozessor ersetzt GPIOA_BASE also durch ((GPIO_TypeDef *) > GPIOA_BASE) Die ursprüngliche Zeile war ja: #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) Ersetzt wird doch das GPIOA mit ((GPIO_TypeDef *) GPIOA_BASE) vom Preprozessor? Oder habe ich dich jetzt falsch verstanden? Wenn man ganz einfach nur die Datentypen betrachtet sieht der Cast rechts doch folgendermaßen aus: (GPIO_TypeDef *) uint32_t Diese Typenumwandlung verstehe ich nicht ganz. Eine Integerzahl, welche eine Adresse darstellen soll, wird in einen Zeiger umgewandelt ?
Alex schrieb: > Diese Typenumwandlung verstehe ich nicht ganz. Eine Integerzahl, welche > eine Adresse darstellen soll, wird in einen Zeiger umgewandelt ? fop hat ja schon ausgerechnet was der Wert der Zahl ist. Den wirst du so auch im Datenblatt des Prozessors als Adresse für die GPIOA finden. Normalerweise kann man Zahlen nicht einfach als Pointer verwenden, außer man weiß was man tut und das ist hier auch der Fall. Mit dem Cast sagst du dem Compiler folgendes: Hier ist eine Zahl und ich bin mir 100% sicher, dass diese Zahl eine Adresse ist, an der eine Struktur des Typs GPIO_TypeDef liegt (In diesem Fall Register, die auf diese Adresse gemapped sind und kein RAM.). Im weiteren kannst du dann über den Pointer auf die Struktur zugreifen und musst die einzelnen Adressoffsets der Register nicht einzeln ausrechnen.
Alex schrieb: > Eine Integerzahl, welche > eine Adresse darstellen soll, wird in einen Zeiger umgewandelt ? Ja. Zum Beispiel (void*) 42 würde einen typlosen Zeiger darstellen der auf die Adresse 42 zeigt (bzw auf die Adresse die sich ergibt wenn man die Zahl 42 als Adresse interpretieren würde was ja ziemlich leicht ist bei einer Architektur bei der der ganze Speicher linear adressiert wird und man jede Adresse auch als Zahl eindeutig ausdrücken kann). Das macht man aber natürlich tunlichst nur bei Adressen die hart verdrahtet oder aus anderen Gründen immer fest sind, alle anderen Zeiger (solche auf Variablen zum Beispiel) sollte man dem Compiler überlassen denn der kann die hinlegen wo er es für richtig erachtet.
:
Bearbeitet durch User
Alex schrieb: > (GPIO_TypeDef *) uint32_t > > Diese Typenumwandlung verstehe ich nicht ganz. Eine Integerzahl, welche > eine Adresse darstellen soll, wird in einen Zeiger umgewandelt ? Die struct bildet die Struktur des Peripherals ab. Bedeutet: Die Offsets der member der Struktur entsprechen den gleichnahmigen Registern des jeweiligen Peripherals. Mit dem "Zusammenführen" wird dem Compiler jetzt gesagt, dass an der Adresse x ein Stück Speicher liegt, vom Typ der Struktur. Greifst du jetzt auf ein Member der Struktur zu, so rechnet der Compiler die Startadresse plus den Offset innerhalb der Struktur als Adresse für den Zugriff. Schaut nach CMSIS aus. Solche Headerfiles aus SVD zu generieren ist spassig. Geht wunderbar in C/C++, wenn man sich Tabellen für verschachtelte struct/union Konstrukte aufbauen muss, aus welchem die Peripherals manchmal bestehen. Z.B. CRC Peris etc. Siehe SVDConv.exe :-)
:
Bearbeitet durch User
Alex schrieb: > Die ursprüngliche Zeile war ja: Ja und ich habe beschrieben was man damit machen kann. Alex schrieb: > Ersetzt wird doch das GPIOA mit ((GPIO_TypeDef *) GPIOA_BASE) vom > Preprozessor? Oder habe ich dich jetzt falsch verstanden? Genau Alex schrieb: > Diese Typenumwandlung verstehe ich nicht ganz. Eine Integerzahl, welche > eine Adresse darstellen soll, wird in einen Zeiger umgewandelt ? Genau. Der Hintergrund ist, das man den Komfort haben möchte über eine Struktur auf die einzelnen Registerinhalte zugreifen zu können. Man definiert also die Struktur GPIO_TypeDef um den Aufbau der Register zu beschreiben. Damit ist aber noch nicht beschrieben wo diese Struktur zum Einsatz kommt (Adresse). Also wird eine Adresse (int) auf einen Pointer vom Typ GPIO_TypeDef gecastet. Erst jetzt weiß der Compiler das er auf die angegebene Adresse über die Strukturfelder zugreifen kann.
Die Antwort auf die Frage : "Kann ich aus einer Integerzahl einen Pointer machen ?" ist gar nicht so sicher, wie viele denken. Normalerweise wird in eigentlich jeder Prozessorarchitektur der Speicher durchnummeriert. Hätte der Ikea - Gründer statt Möbel Mikrcontroller gebaut, hätte er stattdessen den Speicherzellen vielleicht auch schwedische Begriffe als Namen, um sie anzusprechen, gegeben. Dann würde ein Programmierer, der einen Compiler für das Ding baut, einen Zeiger auf Speicherstellen ganz anders umsetzen. Wie ein Compiler Zeiger umsetzt ist dessen Erstellern überlassen. In Systemen, in denen man Speicherstellen über eine Zahl auswählt, wird mit sehr hoher Wahrscheinlichkeit also auch eine Zahl genutzt, um den Wert eines Pointers darzustellen. Damit ist es dann möglich zu schreiben, tu mal so als ob das Ergebnis von 6*9 ein Zeiger wäre. Und es führt eigentlich immer zu dem Ergebnis, dass beim Dereferenzieren dieses Zeigers die eigentlichen Daten auf Adresse 54 gesucht werden. Praktisch, wenn Dateien mit solchen Tricks zusammen mit dem Compiler geliefert wurden. Dann kann man sich doch sicher sein, dass die Tricks mit dem Compiler so funktionieren, wie geplant.
1 | (uint32_t)0x40000000 |
ist übrigens auch so ein Typecast. Betrachte die Zahl 0x40000000 als 32 Bit lange Zahl ohne Vorzeichen. 0x40000000 alleine ist eine Zahl mit Vorzeichen, in der Lieblingslänge der Ersteller des Compilers.
Könnte man dann auch anstelle von: #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) schreiben: GPIO_TypeDef* GPIOA = ((GPIO_TypeDef *) GPIOA_BASE); ? also rein von der Richtigkeit der Syntax
:
Bearbeitet durch User
Wahnsinn Was für ein geniales Forum! Soviele wertvolle Antworten, welche man so in keinem Buch findet. Ich wünschte ich wäre schon früher auf euch gekommen :) Diese #define Sachen werden also nur textmässig ersetzt und dienen nur der Übersichtlichkeit und Einfachheit für den Programmierer. Dieser Cast wird erst dann wirklich durchgeführt, wenn er an der Stelle im Code vom Compiler eingesetzt wird und nicht schon in der #define Anweisung selbst. Hier schaut der Preprozessor, wo ist der linke text und wird durch den rechten text ausgetauscht. Vielen Dank erstmal Euch allen
fop schrieb: > Wenn man jetzt mal selber diese Konstanten aufaddiert, bleibt von diesem > Ausdruck((GPIO_TypeDef *) 0x40010800)übrig. > Also ein Zeiger auf eine Struktur vom Typ GPIO_TypeDef, die auf Adresse > 0x40010800 zeigt. > Verwendet wird das Ding in dem manGPIOA->ODR=42UL;schreibt. Das > Dereferenziert den Zeiger und wählt das Element ODR der > Struktur. Ich habe noch ein Verständnisproblem mit dem Casten: #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) von C her kenne ich das Casten eines Pointers z.B.. wenn ich einen Char Pointer auf INT caste, dann sieht das so aus: int* ptr; char* cPtr = "S"; ptr = (int*) cPtr; dann weiss ich, dass ptr ein int-zeiger auf eine ursprüngliche Char-Adresse ist. anders wäre doch wenn ich nur: (int*) cPtr; schreiben würde, wie es ja grundsätzlich bei ((GPIO_TypeDef *) GPIOA_BASE) der Fall ist. ich vermisse da ein "=" also eine Zuweisung damit ich mit diesem gecasteten Pointer etwas anfangen kann. Ein Cast erzeugt doch kein Objet der Struktur GPIO_TypeDef oder denke ich hier viel zu kompliziert ?
Alex schrieb: > int* ptr; > char* cPtr = "S"; > ptr = (int*) cPtr; > > dann weiss ich, dass ptr ein int-zeiger auf eine ursprüngliche > Char-Adresse ist. Streng genommen weißt Du das nicht. Tatsächlich ist es sogar nicht unwahrscheinlich, daß das undefined behaviour ist (nämlich dann, wenn das alignment nicht paßt). Wenn Du sicherstellen willst, daß der pointer cast kein UB ist, mußt Du erst sicherstellen, daß der char-Pointer das korrekte Alignment hat (sicher ist das beispielsweise, wenn der Zeiger ursprünglich als cast aus einem int-pointer entstanden ist oder der char Teil einer union ist, die int-alignment erzwingt).
darum ging es mir jetzt nicht, aber ich weiss schon was du meinst: wenn ich mit einem pointer-cast plötzlich undefinierten inhalt bekomme kann schnell was schief gehen mein Problem war das denken in Adressen. Die C Programmierung für einen Microkontroller ist ein ganzes Stück anders, als das "gewöhnliche" C was ich noch gelernt hab. Schlimm finde ich dann noch, wenn man die Headerdateien von so einem STM32F1xx anschaut, wie verschachtelt alles ist. Tausende #defines preprozessor anweisungen wo man Schritt für Schritt zurückgehen muss, bis man dann endlich am Ursprung ist. Oder man froh ist wenn man mal ein bekanntes Wort wie "struct" findet und sonst nur benutzerdefinierte typen-namen typedefs und defines.. Klar, so funktioniert gut strukturierte Programmierung, aber ich tue mich da noch ziemlich schwer, zumal ich mir das alles selber beibringen möchte . ich pauke jeden Tag :)
Alex schrieb: > ich vermisse da ein "=" also eine Zuweisung damit ich mit diesem > gecasteten Pointer etwas anfangen kann. Ein Cast erzeugt doch kein Objet > der Struktur GPIO_TypeDef oder denke ich hier viel zu kompliziert ? Das "=" wird dann auch irgendwo im Programm im Zudammenhang mit dem definiertem Makro verwendet. Irgendwo wird dann stehen:
1 | GPIOA = 15; // Da ist Dein "=" |
Der Präprozessor macht daraus
1 | ((GPIO_TypeDef *) 0x40010800) = 15; |
Brummbär schrieb: > Irgendwo wird dann stehen:GPIOA = 15; // Da ist Dein "=" > Der Präprozessor macht daraus((GPIO_TypeDef *) 0x40010800) = 15; Danke Brummbaer für Deine Anwort ! hier ist es aber nicht so: GPIOA->CRL = (1 << 21); denn das ist genau das: ((GPIO_TypeDef *) ((((uint32_t)0x40000000) + 0x10000) + 0x0800))->CRL = (1 << 21); der Cast an sich wirkt wie ein Zeiger auf ein instanziertes Objekt vom Typ GPIO_TypeDef bei der Aresse 0x40010800 Das ist der Knackpunkt weil ich das von C her so nicht kenne. Ein Cast ist/war für mich bisher eine Typenumwandlung, aber kein Erzeugen einer Variable oder eines Zeigers, denn mit: (int*) cPtr; passiert doch erstmal auch nichts weil ich das nichts zuweise wie z.b. mit: int ptr = (int*) cPtr; (als Beispiel)
was ich genau meine ist, dass ich mit GPIOA->CRL gleich auf den Member CRL eines plötzlich bestehenden Objektes zugreifen kann. GPIOA ist doch erstmal nur ein cast, und keine Zuweisung einer Adresse an eine Pointervariable oder habe ich hier einen "Knick in der Optik" ?
Alex schrieb: > Das ist der Knackpunkt weil ich das von C her so nicht kenne. Ein Cast > ist/war für mich bisher eine Typenumwandlung, aber kein Erzeugen einer > Variable oder eines Zeigers, Genau das passiert doch: Der Wert 0x40010800 (vom Typ "int") wird genommen und dessen Typ wird auf "GPIO_TypeDef *" geändert. Mehr passiert nicht. Was sich ändert, ist die Interpretation von "0x40010800 ist eine Zahl" zu "0x40010800 ist die Adresse von einem GPIO_TypeDef". Eine Variable ist ein Stück Speicher mit einem Wert drin. Eine Zeigervariable ist ein Stück Speicher mit einem Zeiger drin. Daraus folgt: Eine Zeigervariable ist eine besondere Variable, und ein Zeiger ist ein besonderer Wert. Also bitte verwechsle "Zeiger" (eine Zahl) nicht mit "Zeigervariable" (ein Stück Speicher).
Alex schrieb: > Ein Cast > ist/war für mich bisher eine Typenumwandlung Und genau das ist es nicht. Es wird hier nichts umgewandelt, sondern nur anders interpretiert. Normalerqweise verhindert die Typenprüfung, dass Du einem Zeiger kein Integer zuweisen kannst. Diese Prüfung wird mit einem Cast außer Kraft gesetzt.
S. R. schrieb: > Der Wert 0x40010800 (vom Typ "int") wird genommen und dessen Typ wird > auf "GPIO_TypeDef *" geändert. Mehr passiert nicht. > > Was sich ändert, ist die Interpretation von "0x40010800 ist eine Zahl" > zu "0x40010800 ist die Adresse von einem GPIO_TypeDef". Ok dann ist das ein Pseudo-Zeiger ? also nicht wie im klassichen C: int a; int*ptr = &a; ptr ist ein int zeiger auf die adresse von a während: ((GPIO_TypeDef *) 0x40010800) ein Cast ist: INT zahl wird von nun an als Adresse interpretiert. Als Adresse darum, weil ich ein "*" Sternchen angebe. Wenn etwas als Adresse interpretiert werden soll, ist das für den Compiler automatisch ein Zeiger auch wenn ich hier keinen Zeigernamen habe sondern "nur" eine Adresse worauf gezeigt wird, muss ich auch den gesamten Cast-Ausdruck dem Compiler immer wieder vor die Nase legen richtig ? Ich glaube die Antwort auf mein Verständisproblem hätte ich wenn ich wüsste wie ein Compiler denkt, dies interpretiert
Alex schrieb: > muss ich auch den gesamten Cast-Ausdruck dem > Compiler immer wieder vor die Nase legen richtig ? Der Compiler will eben wissen welchen Typ er verabeiten soll (ein Kernprinzip von C ist es ja dass die Typen festgelegt sind) Wenn du eine Nummer hinschmeißt musst du halt dazu sagen was es ist. Im Laden sagst du halt ich will 5 (Äpfel) und 5 (Eier) und 0x20 (kilo Hackfleisch) - ist das gleiche Prinzip
Alex schrieb: > Ok dann ist das ein Pseudo-Zeiger ? also nicht wie im klassichen C: Das ist klassisches C. Ein Zeiger ist einfach eine Zahl die zudem den Typ "Zeiger" hat. Wenn Du eine Zahl vom Typ "Integer" hast und diese einem Zeiger zuweisen willst, wirst Du mit einem Fehler darauf hingewiesen. Wenn Du aber 100%ig sicher bist, das das trotzdem gemacht werden soll, schreibst Du einen Cast vorweg. Die Zahl bleibt immer noch eine Zahl. Der gecastete Integer ist dann ein echter Zeiger und nicht nur ein merkwürdiges Konstrukt.
Das ist kein "Pseudozeiger". Es ist ein Link zu einem Stück Speicher mit einer Adresse. Bei deinem Beispiel berechnest du die Adresse vom int a über den & Operator und weist ihn einer Variablen ptr, zu. ptr ist ebenfalls ein Stück Speicher, der nur jetzt eben mit der Adresse von a belegt ist. Eine Abkürzung sozusagen, du könntest auch *(&a) = 4; schreiben. Jetzt kommt aber der Trick: Anstatt, dass du die Adresse von a mit & herausbekommen musst, ist die GPIOA_BASE Adresse vorher bekannt. Definiert durch ST Micro. Also brauchst du die Variable ptr nicht - es ist ein Platzhalter und eine nette Möglichkeit vom Compiler, die Adresse von a automatisch ermitteln zu können. Brauchst du nicht, du willst ja die Speicherstelle direkt ansprechen, weil du nämlich weist, dass dort die Register deines GPIOA liegen und zwar genau in der Form, wie sie dein GPIO_TypeDef struct zeigt. Das ist aber per Design so, nicht einfach so. Natürlich kannst du auch sowas schreiben: GPIO_TypeDef * myPtr = GPIOA; und dann über myPtr->RegA ansprechen. Aber möchtest du jedes Mal eine neue Variable im Ram erstellen, um dein GPIO anzusprechen?
Vielen Dank für Eure Antworten. Ihr erklärt das wie aus Sicht des Compilers. Ich dachte ich hätte Zeiger und deren Syntax schon verstanden, aber der Cast hat mir eigentlich das Gegenteil gezeigt... aber vieles was ich jetzt von euch erklärt bekommen habe findet man in keinem Lernbuch so erklärt. Ich denke der "Groschen" ist jetzt auch bei mir gefallen. Ich werde jetzt erstmal mit dem hier weiter üben gehen
Es hat funktioniert !! Ohne dass ich eine Pointer Variable gebraucht habe: #include <stdio.h> #include <stdlib.h> int main() { int a = 20; *(&a) = 10; printf("Variable A hat jetzt den Wert:%d\n",a); return 0; } ich wollte hiermit ausprobieren, was mein Vorredner Jan erklärt hat mit der kürzeren Schreibweise. Jetzt habe ich aber einen Typenlosen Zeiger der auf die Adresse von a zeigt ?
Alex schrieb: > *(&a) = 10; Du hast einen dereferenzierten Zeiger auf "a". Also wieder die Variable selber.
Brummbär schrieb: > Du hast einen dereferenzierten Zeiger auf "a". Also wieder die Variable > selber. ok, aber muss ich beim Zeigen nicht wissen auf welchen Datentyp ich zeige ?
Der Compiler weiß, dass der Datentyp von a ein int ist. Daher weiß er auch dass &a ein Zeiger auf eine Int-Variable und *(&a) wieder die Int-Variable selber ist.
Brummbär schrieb: > Der Compiler weiß, dass der Datentyp von a ein int ist das habe ich befürchtet :D
Alex schrieb: > Brummbär schrieb: >> Du hast einen dereferenzierten Zeiger auf "a". Also wieder die Variable >> selber. > > ok, aber muss ich beim Zeigen nicht wissen auf welchen Datentyp ich > zeige ? Wenn Du das "nachbauen" willst, mach' so:
1 | float a = 20.0; |
2 | int ad = (int) &a; // die Adresse von a als int |
3 | |
4 | * (float *) ad = 22.0; |
Markus F. schrieb: > Wenn Du das "nachbauen" willst, mach' so: > float a = 20.0; > int ad = (int) &a; // die Adresse von a als int > > * (float *) ad = 22.0; ok 1. a bekommt wert 20.0 vom typ float 2. int ad speichert adresse von a als int-zahl (gecastet) 3. ad wird floatzeiger und zeigt wieder auf a und überschreibt den inhalt mit 22.0 int a ist nun 22.0 !! also bei der letzten Zeile kam ich ganz schön ins straucheln und musste bestimmt 5 minuten überlegen .. vllt habe ich für heute auch zuviel gemacht. ich werde morgen die Sache nochmals angehen. Gute Nacht
Alex schrieb: >> Der Wert 0x40010800 (vom Typ "int") wird genommen und dessen Typ wird >> auf "GPIO_TypeDef *" geändert. Mehr passiert nicht. >> >> Was sich ändert, ist die Interpretation von "0x40010800 ist eine Zahl" >> zu "0x40010800 ist die Adresse von einem GPIO_TypeDef". > > Ok dann ist das ein Pseudo-Zeiger ? Nein, das ist ein Zeiger wie jeder andere auch. > also nicht wie im klassichen C: > > int a; > int*ptr = &a; > > ptr ist ein int zeiger auf die adresse von a Das steht oft so geschrieben, aber ptr ist eine Zeigervariable, die einen Zeiger auf die Adresse von a enthält. Ein Zeiger ist eine Zahl. Eine Zeigervariable ist eine Variable. Der Unterschied muss dir im Kopf klar sein, es wird aber nur selten so klar unterschieden (auch in Lehrbüchern nicht). > während: > ((GPIO_TypeDef *) 0x40010800) > ein Cast ist: INT zahl wird von nun an als Adresse interpretiert. Es gibt kein "von nun an". Du hast den Compiler gezwungen, diese eine Zahl in diesem einen Ausdruck für dieses eine Mal anders zu interpretieren, als er es sonst gemacht hätte. Genau das ist ein Cast. > Als Adresse darum, weil ich ein "*" Sternchen angebe. > Wenn etwas als Adresse interpretiert werden soll, ist das für den > Compiler automatisch ein Zeiger Genau. In C werden Zeigertypen mit Sternchen markiert. Zeiger und Adressen sind das gleiche (die historischen Sonderfälle, wo das nicht gilt, ignoriere ich jetzt mal). > auch wenn ich hier keinen Zeigernamen habe sondern "nur" eine Adresse > worauf gezeigt wird, muss ich auch den gesamten Cast-Ausdruck dem > Compiler immer wieder vor die Nase legen richtig ? Richtig, weil du jedesmal, wenn du eine vom Normalfall abweichende Interpretation haben willst, den Compiler erneut dazu zwingen musst.
Das a->b nur eine Abkürzung für (*a).b ist, ist Dir bekannt, oder liegt da das Problem?
S. R. schrieb: > Der Unterschied muss dir im Kopf klar sein, es wird aber nur selten so > klar unterschieden (auch in Lehrbüchern nicht). Vielen Dank Svenska, du hast damit tatsächlich eine Schwachstelle bei mir gefunden. Meine Denkweise über Zeiger war hier immer völlig falsch. Der Cast muss dem Compiler jedesmal aufgezwungen werden Und ganz wichtig : Der Zeiger ist eine Zahl und keine Zeigervariable. Eine Zeigervariable enthält nur diese Zahl die ein Zeiger ist. Eine Zeigervariable ist aber nicht immer nötig (wie bei diesem Cast z.B.)
Dumdi D. schrieb: > Das a->b nur eine Abkürzung für (*a).b ist, ist Dir bekannt, oder liegt > da das Problem? Hallo Dumdi, ja das war mir zum Glück schon bewusst.
Ein vollwertiger Zeiger auf die Adresse 0x40010800 ist: ((GPIO_TypeDef*) 0x40010800) 0x40010800 nach dem cast ist wieder eine ganz normale zahl Deswegen habe ich immer verzweifelt nach einer Pointer-Variable gesucht und nie verstanden
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.