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 | .... dataTable kriegt Speicher und Werte
|
4 |
|
5 |
|
6 | void foo()
|
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 | .... dataTable kriegt Speicher und Werte
|
und auf die Funktion vergisst er, bzw. das weiss er alles nicht mehr. Da
steht nach wie vor
1 | void foo()
|
2 | {
|
3 | int* myData = (int*)dataTable;
|
4 |
|
5 | *myData = 8;
|
6 | }
|
Tja. Und das geht in die Hose. Ohne Cast
1 | void foo()
|
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.