Der Typ "void *" in C (Der Typ "void *" in C ), Lektion, Seite 722997
https://www.purl.org/stefan_ram/pub/void_pointer_c (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C-Kurs

Der Typ »void *« in C 

Eine Adresse enthält normalerweise zwei  Informationen: Die Position  und die Größe  ihres Referenten. Solch eine normale Adresse nennen wir auch eine Objekt-Adresse.

Eine void-Adresse ist eine Adresse, der die zweite Information fehlt. Es handelt sich nur noch um eine Speicherposition, die aber keine  Information über die Größe des Objekts an dieser Stelle mehr enthält.

Konvertierungen

Eine void-Adresse darf in eine Objektadresse gewandelt werden.

Eine Objekt-Adresse darf in eine void-Adresse gewandelt werden.

Wenn eine Objekt-Adresse in eine void-Adresse gewandelt wird und das Ergebnis dann wieder zurück in den ursprünglichen Objekt-Adreß-Typ gewandelt wird, dann ergibt sich wieder die ursprüngliche Objekt-Adresse.

Hin- und Herwandlung

Wenn eine Objektadresse in eine void-Adresse gewandelt wurde, kann sie wieder in den ursprünglichen Adreßtyp zurückgewandelt werden, was dann ein Adresse ergibt, welche deren Vergleich mit der ursprünglichen Objektadresse »[1]« ergibt.

main.c

#include <stdio.h>

int main( void )
{ int i = 27;
int * p = &i;
void * v = p;
int * r = v;
printf( "%d\n", p == r ); }

Protokoll
1

Bei einer void-Adresse »v« kann »sizeof *v« beispielsweise nicht  ausgewertet werden.

main.c

#include <stdio.h>

int main( void )
{ int i = 27;
int * p = &i;
void * v = p;
printf( "%zu\n", sizeof *vp ); }

Protokoll
error: invalid application of 'sizeof' to a void type

Eine void-Adresse in einem ternären Ausdruck

Wenn der Typ eines Zweiges eines ternären Ausdrucks eine void-Adresse und der Typ des anderen Zweiges eine Objektadresse ist, dann hat der gesamte ternäre Ausdruck den Typ »void *«

main.c

#include <stdio.h>

int main( void )
{ int i = 27;
int * p = &i;
void * v = p;
printf( "%zu\n", sizeof( *( 1 ? p : v ))); }

Protokoll
error: invalid application of 'sizeof' to a void type

Vergleich mit einer Objektadresse

Wenn eine Objektadresse mit einer void-Adresse verglichen wird, wird sie zuvor implizit in eine void-Adresse gewandelt.

Unten erfolgt der Vergleich »q == p« also, als hätte man geschrieben »( void * )q == p«.

main.c

#include <stdio.h>

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

Protokoll
1

Dereferenzierung einer void-Adresse

Bei Verwendung einer void-Adresse »p« wird kein Objekt  referenziert, weswegen die Dereferenzierung »*p« einer solchen Adresse auch kein Objekt  ergibt, und es gibt nur wenig, was man mit solch einem void-Ausdruck tun kann. Im folgenden Programm wird der Wert des Ausdrucks »*q« einmal verworfen, und dann wird die Adresse »&*p« mit »p« verglichen (was »[1]« ergeben muß).

main.c

#include <stdio.h>

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

Protokoll
1

»%p« — Ausgabe von Adressen

Eine void-Adresse kann mit dem Formatierungsbuchstaben »p« (“pointer ”) ausgegeben werden. Adressen eines anderen Typs dürfen nicht auf diese Weise ausgegeben werden, sondern müssen erst in eine void-Adresse gewandelt werden. Jedoch darf der void-Zeiger mit »const« modifiziert worden sein.

main.c

#include <stdio.h>

int main( void )
{ int i = 27;
int * p = &i;
void * v = p;
printf( "%p\n", v ); }

Protokoll
000000000022fe4c
Protokoll (ältere C -Implementation)
0022feb4

Die genaue Art und Weise, wie ein Zeiger als Text dargestellt wird ist implementationsdefiniert.

Ausgabe von Adressen von Variablen von Inkarnationen

Wir können nun die unterschiedlichen Adressen der Variablen (Parameter) unterschiedlicher Inkarnationen einer Funktion ausgeben.

main.c

#include <stdio.h>

void f( int const i )
{ if( i < 4 )
{ void const * const v = &i;
printf( "%d, %p\n", i, v );
f( i + 1 );
printf( "%d, %p\n", i, v ); }}

int main( void ){ f( 0 ); }

Protokoll
0, 000000000022fe30
1, 000000000022fe00
2, 000000000022fdd0
3, 000000000022fda0
3, 000000000022fda0
2, 000000000022fdd0
1, 000000000022fe00
0, 000000000022fe30

Undefininiertes Verhalten

Das Auslesen einer nicht-initialisierten lokalen Variablen hat undefiniertes Verhalten. In bestimmten Fällen kann der Wert eine Variablen einer anderen Funktion  ausgelesen werden, die sich an derselben Adresse befindet. Eventuell können interne Details einer anderen Funktion auf diese Weise ausspioniert werden.

main.c

#include <stdio.h>

void f() { int i; printf( "f %p, %2d\n",( void * )&i, i ); i = 24; }

void g() { int i; printf( "g %p, %2d\n",( void * )&i, i ); i = 64; }

void h() { int i; printf( "h %p, %2d\n",( void * )&i, i ); i = 12; }

int main(){ f(); g(); h(); }

Protokoll
f 000000000022fe4c,  0
g 000000000022fe4c, 0
h 000000000022fe4c, 0

Nulladreßkonstanten

Wir hatten schon »0« als Nulladreßkonstante kennengelernt. Auch »(( void * )0 )« darf als Nulladreßkonstante verwendet werden.

 

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 stefanram722997 stefan_ram:722997 Der Typ "void *" in C Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722997, slrprddef722997, 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/void_pointer_c