Warum verwende ich einen void-Zeiger, um Variablen von Datentypen zu dereferenzieren?

8

Dereferenzierung einer float-Variablen mit einem void-Zeiger:

%Vor%

Ausgabe: 7.500000

Dereferenzierung einer Variablen mithilfe eines ganzzahligen Zeigers:

%Vor%

Ausgabe: 7.500000

In beiden sind die Ausgänge gleich. Was ist der Grund für die Dereferenzierung verschiedener Datentypvariable, wenn wir einen normalen Zeiger typisieren können?

    
Jaivvignesh 25.08.2017, 05:40
quelle

3 Antworten

5

Ein void -Zeiger ist ein generischer Zeiger , der die Adresse eines beliebigen Typs enthalten kann und typecast zu jedem Typ.

Im ersten Fall wurde das Programm erfolgreich kompiliert und ohne Warnung oder Fehler ausgeführt, da die Verwendung eines void Zeigers zum Konvertieren von einem Zeigertyp in einen anderen und Speichern oder Umwandeln in den endgültigen Typ sicher ist, ohne Daten zu verlieren .

Aber im zweiten Fall hat der GCC Compiler eine Warnung generiert

%Vor%

Sprachcompiler:

%Vor%

Der C11-Standard, 6.3.2.3, Absatz 7:

  

Ein Zeiger auf ein Objekt oder einen unvollständigen Typ kann in a konvertiert werden   Zeiger auf ein anderes Objekt oder unvollständiger Typ . Wenn das Ergebnis   Zeiger ist nicht korrekt für den referenzierten Typ, das Verhalten ausgerichtet   ist undefiniert .

    
rsp 25.08.2017, 06:10
quelle
14

Das Konvertieren eines Datenzeigers in void* Zeiger und zurück gibt garantiert den ursprünglichen Zeiger zurück.

Ab C11 Standardentwurf N1570:

  

6.3.2.3 Zeiger

     
  1. Ein Zeiger auf void kann in oder von einem Zeiger auf einen beliebigen Objekttyp konvertiert werden. Ein Zeiger auf   jeder Objekttyp kann in einen Zeiger auf void und zurück konvertiert werden; das Ergebnis soll   Vergleiche mit dem ursprünglichen Zeiger.
  2.   

Konvertieren von Datenzeiger zu einem anderen Datenzeiger als void* ( int* in Ihrem Beispiel) kann funktionieren. Es hängt vom verwendeten Compiler und dem System ab, auf dem Sie sich befinden. Nicht alle Systeme verwenden möglicherweise dieselbe interne Repräsentation für unterschiedliche Zeigertypen.

  
  1. Ein Zeiger auf einen Objekttyp kann in einen Zeiger auf einen anderen Objekttyp umgewandelt werden. Wenn die   resulting pointer ist nicht richtig ausgerichtet 68 für den referenzierten Typ ist das Verhalten   nicht definiert. Andernfalls wird das Ergebnis, wenn es wieder zurückverwandelt wird, gleich dem Wert von   Original-Zeiger. Wenn ein Zeiger auf ein Objekt in einen Zeiger auf einen Zeichentyp konvertiert wird,   Das Ergebnis zeigt auf das niedrigste adressierte Byte des Objekts. Aufeinander folgende Inkremente des   Ergebnis, bis zur Größe des Objekts, Zeiger auf die verbleibenden Bytes des Objekts.
  2.   

Dies unterscheidet sich von strengen Aliasregeln .

%Vor%

Der obige Code bricht die strikte Alias-Regel, da der dereferenzierte Typ nicht mit dem ursprünglichen Typ übereinstimmt. Dies führt zu undefiniertem Verhalten und ist immer ungültiger Code.

    
user694733 25.08.2017 06:07
quelle
4

Ein void -Zeiger ist (irgendwie) untypisiert. Es kann auf alles zeigen, ohne dass sich der Compiler beschweren muss. z.B. Wenn Sie eine int Variable haben, können Sie sicher einen void Zeiger erstellen, der darauf zeigt und ihn weitergibt. z.B.

%Vor%

ist in Ordnung, aber

%Vor%

wird den Compiler stören

Dies ist besonders nützlich für Funktionen, die mit mehreren Zeigertypen arbeiten oder wenn Sie entscheiden, was zur Laufzeit ist.

void-Zeiger können jedoch nicht direkt dereferenziert werden ( * ), da der Compiler seinen Typ nicht kennt. Also,

%Vor%

bricht ab, wenn p ein ungültiger Zeiger ist. Wir müssen die Größe dessen wissen, worauf es hinweist, um es zu dereferenzieren, und dies geschieht mit einer manuellen Typumwandlung (wie Sie es getan haben).

In Ihrem speziellen Fall haben Sie einen Zeiger, der auf einen Float zeigt, den Sie vor dem Drucken in Float einschreiben. So erhalten Sie die gleiche Ausgabe. Der Zeiger void * spielt hier nicht wirklich eine große Rolle.

Ein Beispiel dafür, wo Sie eine void * benötigen, ist die Funktion malloc . Wenn Sie sich den Prototyp ansehen, wird eine void * zurückgegeben. ein Block aus Rohspeicher. Sie müssen dies als konkreten Typ eingeben, bevor Sie Zeigerarithmetik und Dereferenzierung durchführen können.

    
Noufal Ibrahim 25.08.2017 06:16
quelle