Was hat es mit der vorletzten Zeile auf sich? Für mich sieht das aus als
ob der Zeiger *gpioBaseMem auf *gpioBaseMem gecasted wird - was ich für
wirres Zeug halten würde. Oder hat das seinen Grund?
naja outPin ist vom Datentyp int. GPSEL0 wird nicht klar was das für ein
Datentyp ist. Da es in der 2ten Klammer der vorletzten Zeile zu einer
implizieten Typumwandlung kommt, wandelt man mit (volatitle uint32_t*)
wieder zurück zum richtigen Typ. Kann man durchaus so machen.
schlau-werden-Wollender schrieb:> Für mich sieht das aus als> ob der Zeiger *gpioBaseMem auf *gpioBaseMem gecasted wird - was ich für> wirres Zeug halten würde. Oder hat das seinen Grund?
Ich hätte jetzt gesagt, dass die geklammerten Berechnungen für den
Zeiger mit einem Defaulttyp ausgeführt werden. Da dieser sich von der
Zeigerbreite unterscheiden kann, teilt man dem Compiler per Cast mit,
welche Bitbreite er für temporäre Ergebnisse verwenden soll.
ccccccc schrieb:> naja outPin ist vom Datentyp int. GPSEL0 wird nicht klar was das für ein> Datentyp ist.schlau-werden-Wollender schrieb:> mit der vorletzten Zeile
sieht für mich aus wie ganz normale Zeigerarithmetik:
fSelAddr = gPioBaseMem + irgendwie berechneter Offset
Der Typecast davor dient dazu, auch das Ergebnis 'volatile' zu machen.
Autor: ccccccc (Gast) schrieb:
>GPSEL0 wird nicht klar was das für ein>Datentyp ist.
Das gehört noch dazu:
1
#define GPFSEL0 0x00000000 //gpio function select. There are 6 of these (32 bit registers)
Sehe ich das richtig: Du meinst, daß:
int outPin = 10;
den Zeiger hier;
uint32_t *gpioBaseMem
auf ein int castet? Oder es zumindest zu einer Warnung/Fehlermeldung
kommt?
Der Cast muss ja nicht unbedingt gemacht werden. Sprich
1
(gpioBaseMem+GPFSEL0/4+outPin/10)
kann auch den richtigen Datentyp zurückgeben, das weiß ich jetzt nicht
auswendig. Allerdings ist es schöner das ganze nochmal explizit
darzustellen, dass das Ergebniss der Berechnung nochmal mit
1
(volatileuint32_t*)
zu casten.
So seh ich das zumindest, jetzt kommt eh gleich wieder: Ja warum
angeben, das wird alles unleserlich. Ich finde man kann solche casts
durchaus nochmal machen. Nach dem Python-Grundsatz: "Explicit is better
than implicit"
Die wahrscheinlichste Erklärung dürfte sein, dass der Programmierer am
Anfang gpioBaseMem noch nicht als Pointer zu volatile hatte und dann
einfach überall ein volatile mit der Gieskanne ergänzt hat. Vielleicht
hatte er auch irgendwelchen Ärger und dann einfach mal rumgecastet. Das
kommt leider häufiger vor, als man denkt, dass wenn etwas nicht so
funktioniert wie man sich das vorstellt, dass dann einfach mal wild
rumgecastet wird.
Rein formal ist der Cast hier nicht notwendig.
ccccccc schrieb:> naja outPin ist vom Datentyp int. GPSEL0 wird nicht klar was das für ein> Datentyp ist. Da es in der 2ten Klammer der vorletzten Zeile zu einer> implizieten Typumwandlung kommt
Das ist Pointer Arithmetik. Das Ergebnis hat denselben Datentyp, wie ihn
der Pointer hatte. Und der ist 'vaoltile uint32_t *'. Ganz ohne Cast.
> Von der Arithmetik her könnte man die Klammer doch auch weglassen, oder?
Dann wär der Cast noch viel unsinniger.
Denn ein Cast bindet am stärksten. Damit wäre
ccccccc schrieb:> Der Cast muss ja nicht unbedingt gemacht werden. Sprich>
1
>(gpioBaseMem+GPFSEL0/4+outPin/10)
2
>
> kann auch den richtigen Datentyp zurückgeben, das weiß ich jetzt nicht> auswendig. Allerdings ist es schöner das ganze nochmal explizit> darzustellen,
Das Problem an dieser Stelle ist dasselbe wie bei jedem Cast, bei dem
ein Pointer umgecastet wird: Es ist eine Waffe, weil man de facto
jegliche Typprüfung des Compilers damit abschaltet.
So etwas macht man nicht, wenn man nicht unbedingt muss!
> durchaus nochmal machen. Nach dem Python-Grundsatz: "Explicit is better> than implicit"
... but not, if you tell the compiler: I don't care if I make a mistake.
I want you to just shut up!
schlau-werden-Wollender schrieb:> Autor: ccccccc (Gast) schrieb:>>GPSEL0 wird nicht klar was das für ein>>Datentyp ist.>> Das gehört noch dazu:>
1
>#defineGPFSEL00x00000000//gpio function select. There are 6 of
2
>these(32bitregisters)
3
>
>> Sehe ich das richtig: Du meinst, daß:> int outPin = 10;> den Zeiger hier;> uint32_t *gpioBaseMem> auf ein int castet?
Jungs.
Ihr müsst schon die C Regeln lernen, wenn ihr C programmieren wollt!
Wie Pointer-Arithmetik in C funktioniert, ist klar geregelt. Ohne
Pointer Arithmetik bleiben dann auch die Feinheiten von Arrays bzw.
Arrayzugriffe auf immer ein Buch mit 7 Siegeln.
[quote]
und da der Datentyp von gpioBaseMem bereits
volatile uint32_t *gpioBaseMem, ...
ist, castet man eine Variable auf ihren eigenen Datentyp. Eine sinnlose,
ja sogar gefährliche, Operation.[/quote]
Sinnlos und überflüssig auf jeden Fall, aber wieso gefährlich?
mameluk schrieb:> [quote]> und da der Datentyp von gpioBaseMem bereits>> volatile uint32_t *gpioBaseMem, ...>> ist, castet man eine Variable auf ihren eigenen Datentyp. Eine sinnlose,> ja sogar gefährliche, Operation.[/quote]> Sinnlos und überflüssig auf jeden Fall, aber wieso gefährlich?
Denk mal darüber nach, welche Falle sich auftut, wenn sich Datentypen
ändern.
Gut, ist in diesem Fall nicht sehr wahrscheinlich. Aber im allgemeinen
Fall.
1
int*dataTable;
2
3
....dataTablekriegtSpeicherundWerte
4
5
6
voidfoo()
7
{
8
int*myData=(int*)dataTable;
9
10
*myData=8;
11
}
So weit so gut. Nichts spezielles passiert hier. Der Cast ist zwar
überflüssig, ist aber an und für sich kein Problem.
Die Zeit vergeht und in ein paar Monaten stellt sich raus, dass
dataTable auf einen double erweitert werden muss. Kein Problem, der
Programmierer ändert den Datentyp
1
double*dataTable;
2
3
....dataTablekriegtSpeicherundWerte
und auf die Funktion vergisst er, bzw. das weiss er alles nicht mehr. Da
steht nach wie vor
1
voidfoo()
2
{
3
int*myData=(int*)dataTable;
4
5
*myData=8;
6
}
Tja. Und das geht in die Hose. Ohne Cast
1
voidfoo()
2
{
3
int*myData=dataTable;
4
5
*myData=8;
6
}
hätte es vom Compiler einen Error gegeben. Denn links vom = steht der
Datentyp 'Pointer auf int', rechts davon steht 'Pointer auf double' und
die beiden können nicht einfach so zugewiesen werden, weil sie nicht
kompatibel sind.
Mit dem Cast hat man aber dem Compiler effektiv gesagt: "Ich weiss, dass
die Datentypen links und rechts nicht zusammen stimmen, das macht aber
nichts. Ich bin der Programmierer und du hältst die Klappe!"
Und genau das macht der Compiler auch. Anstatt einen offensichtlichen
Fehler zu melden (und die richtige Aktion wäre es natürlich den Datentyp
von myData auf 'Pointer auf double' zu ändern) akzeptiert der Compiler
das fehlerhafte Statement gezwungenermassen.
Wenn ein Pointer umgecastet wird, dann wird damit effektiv die
Datentypprüfung abgeschaltet! Am numerischen Wert des Pointers ändert
sich nichts, aber ein anderer Datentyp verursacht bei Derefenzierung
eine andere Aktion (bzw. bei Adressarithmetik), weil da implizit immer
die sizeof dessen auftaucht, worauf der Pointer zeigt.
Die Typprüfung des Compilers willst du aber nicht abschalten. Gerade bei
Pointern nicht. Wenn 2 Pointer nicht datentypkompatibel sind, dann ist
das (abgesehen von den Fällen, in denen ein volatile dazu oder
weggecastet wird) in 980 von 1000 Fällen ein tatsächlicher Fehler!
Natürlich kommt es vor, dass man Pointer auch mal umcasten muss.
Speziell dann, wenn man an die Bytedarstellung von irgendwas ran muss.
Aber abgesehen davon ist das meistens ein Fehler. Daher: Wenn da etwas
nicht stimmt, dann willst du haben, dass der Compiler Feuer schreit. Und
daher willst du den Compiler nicht mit einem Cast ruhig stellen. Auch
nicht vorsorglich. Du schneidest dich damit im schlechtesten Fall nur
ins eigene Fleisch und im besten Fall bewirkt der Cast genau gar nichts
(so wie hier).
Wir alle wissen, dass man sich in C sehr leicht selbst ins Knie
schiessen kann. Du willst jede Hilfe und jede Überwachung vom Compiler
haben, die du kriegen kannst. Die mutwillig einfach abzuschalten, ist
das genaue Gegenteil davon.
Danke für die ausführliche Antwort! :) Auf der Ebene war mir das Problem
klar, ich dachte im vorliegenden Fall hätte ich irgendeine spezielle
Falle übersehen.
Karl Heinz schrieb:> Wir alle wissen, dass man sich in C sehr leicht selbst ins Knie> schiessen kann. Du willst jede Hilfe und jede Überwachung vom Compiler> haben, die du kriegen kannst. Die mutwillig einfach abzuschalten, ist> das genaue Gegenteil davon.
Jepp!
Eine eigene Frage?
Dieser Thread ist über 11 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.