Adreßtypwandlungen in C (Adreßtypwandlungen in C), Lektion, Seite 723829
https://www.purl.org/stefan_ram/pub/zeigertypwandlungen_c (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C-Kurs

Adreßtypwandlungen in C 

Wenn »E « ein Ausdruck und »T « ein Typ ist, dann ist »( T  )E « ein Ausdruck mit dem Typ »T «. Wir nennen solch einen Ausdruck »( T  )E « auch einen cast -Ausdruck, und »( T  )« einen cast -Operator oder cast.

Aussprachehinweis
cast kæst (n) (⌊ˈkæ̣sτ⌋)

Wir interessieren uns hier besonders für die Fälle, in denen »T « ein Adreßtyp und »E« ein Ausdruck mit einem Adreßtyp ist.

Kompatibilität von Typen

Zwei Typen werden als kompatibel  angesehen, wenn sie praktisch gleich sind. Daneben gibt es noch einige Umstände unter denen zwei verschiedene Typen als kompatibel gelten, aber diese sind fast alle so eng gefaßt, daß es im allgemeinen reicht, sich unter zwei kompatiblen Typen zwei gleiche  Typen vorzustellen.

Effektive Typen von Objekten

Der effektive Typ  eines Objektes ist der Typ, mit dem es deklariert wurde.

Nach der Deklaration »int c;« hat das Objekt der Variablen »c« beispielsweise den Typ »int«.

(Wir reden hier von dem „effektiven Typ eines Objektes“, weil Typen zunächst zu Ausdrücken (Variablen) und nicht zu Objekten gehört. Außerdem werden wir später noch Objekte ohne  Deklaration kennenlernen werden, die aber trotzdem einen effektiven Typ haben können.)

Zugriffe auf Objekte

Ein Zugriff auf ein Objekt ist nur mit einem Ausdruck gestattet, der einen Typ hat, welcher zum effektiven Typ des Objekts kompatibel ist oder der in einer der weiter unten behandelten Beziehungen zum Typ des Objektes steht.

Daher ist das folgende Programm nicht  gestattet.

main.c

#include <stdio.h>

int main( void )
{ int n = 123;
double * p =( double * )&n;
printf( "%g\n", *p ); }

Protokoll
1.6976e-313

Der Typ von »*p« ist »double«, aber der effektive Typ des Objekts »n« ist »int«.

Das folgende Programm ist hingegen gestattet, da der Typ von »*p« gleich dem effektiven Typ des Objekts »n« ist, also gleich »int«, ist.

main.c

#include <stdio.h>

int main( void )
{ int n = 123;
int * p =( int * )&n;
printf( "%d\n", *p ); }

Protokoll
123

Qualifizierte Zugriffe

Hinzufügen von »const«

Zusätzlich zum vorgenannten Fall, ist es auch gestattet, daß sich der zum Zugriff verwendete Typ durch die An- oder Abwesenheit einer Qualifikation wie »const« vom effektiven Typ des Objektes unterscheidet.

main.c

#include <stdio.h>

int main( void )
{ int const n = 123;
printf( "%d\n", *( ( int const * const )&n )); }

Protokoll
123

int *« ist kein  Typ, der sich durch die An- oder Abwesenheit einer Qualifikation von »int const *« unterscheidet, da es hierbei nur um Qualifikationen geht, welche ein Objekt jenes Typs direkt betreffen.)

Entfernen von »const«

Es ist auch gestattet, ein »const« zu entfernen, doch wird dies nicht  empfohlen.

main.c

#include <stdio.h>

int main( void )
{ int const n = 123;
printf( "%d\n", *( ( int const * )( int const * const )&n )); }

Protokoll
123

Es ist aber nicht  gestattet, ein konstantes Objekt zu modifizieren, auch wenn dies mit einem Typ erfolgt, der nicht const-modifiziert ist.

C 2017 6.7.3p6 (Zitat)
If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
main.c

#include <stdio.h>

int main( void )
{ int const n = 123;
int * p =( int * )&n;
*p = 456; /* undefined behavior */
printf( "%d\n", n ); }

Protokoll
456

In der Praxis kommt es manchmal vor, daß ein »const« durch eine Typwandlung entfernt wird, wenn ein Objekt verändert werden soll, von dem bekannt ist, daß es nicht konstant ist. Jedoch ist solch eine Typwandlung eigentlich nur ein Symptom für einen Fehler an einer anderen Stelle, der erst dazu führt, daß solch eine Wandlung nötig wird. Im besten Falle sollten solche Wandlungen nie nötig sein.

Zugriffe mit veränderter Vorzeichenregelung

Es ist erlaubt, auf ein Objekt eines numerischen Typs mit einer Adresse mit einer anderen Vorzeichenregelung zuzugreifen. In diesem Falle wird die interne Darstellung des Objektes mit der anderen Vorzeichenregelung interpretiert. Das Verhalten ist dann zwar nicht undefiniert, aber implementationsspezifisch, also nicht portabel.

main.c

#include <stdio.h>
#include <limits.h>

int main( void )
{ unsigned u = UINT_MAX;
signed * sp =( signed * )&u;
printf( "%d\n", *sp ); }

Protokoll
-1

Solche Zugriffe mit veränderter Vorzeichenregelung sind in der Praxis eher selten.

Zugriffe mit char-Typen

Schließlich ist der Zugriff auf ein Objekt mit einer Adresse eines char-Typs gestattet. Dies erlaubt es, die interne Darstellung eines Objektes Byte für Byte „auszulesen“ (ein char-Objekt repräsentiert ein Byte). Wir zeigen hier zunächst den Zugriff auf das Byte, das sich an derselben Stelle wie ein int-Objekt befindet.

main.c

#include <stdio.h>

int main( void )
{ int n = 10000;
printf( "%zu\n", sizeof( n ));
unsigned char * cp =( unsigned char * )&n;
printf( "%d\n", *cp ); }

Protokoll
4
16

Das int-Objekt »n« umfaßt insgesamt vier Byte, und das erste davon hat den Wert »[16]«. Der Zugriff auf die anderen drei Bytes wird später gezeigt werden.

Zitat *

C 2018 6.5p7 (Zitat) (vereinfacht)
6.5 Expressions
7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram723829 stefan_ram:723829 Adreßtypwandlungen in C Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd723829, slrprddef723829, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/zeigertypwandlungen_c