2010-05-31 28 views
6

Ich würde das nachschlagen, aber ehrlich gesagt würde ich nicht wissen, wo ich anfangen soll, weil ich nicht weiß, wie es heißt. Ich habe Variablen auf Funktionen wie diese weitergegeben gesehen:Was bedeutet (void **) in C?

myFunction((void**)&variable); 

Welche das Heck aus mir verwirrt verursachen alle diejenigen mir bekannt vorkommen; Ich habe sie noch nie so zusammen gesehen.

Was bedeutet das? Ich bin ein Newb, also weniger Jargon, desto besser, danke!

Antwort

4

Es ist eine Umwandlung in einen Zeiger auf einen Zeiger void.

Sie sehen dies sehr oft mit Funktionen wie CoCreateInstance() auf Windows-Systemen.

ISomeInterface* ifaceptr = 0; 
HRESULT hr = ::CoCreateInstance(CLSID_SomeImplementation, NULL, CLSCTX_ALL, 
    IID_ISomeInterface, (void**)&ifaceptr); 
if(SUCCEEDED(hr)) 
{ 
    ifaceptr->DoSomething(); 
} 

Der gegossenen wandelt den Zeiger auf einen ISomeInterface Zeiger in einen Zeiger auf einen Zeiger, so dass voidCoCreateInstance()ifaceptr auf einen gültigen Wert einstellen.

Da es sich um einen Zeiger auf einen void Zeiger handelt, kann die Funktion abhängig von der Schnittstellen-ID Zeiger (z. B. IID_ISomeInterface) ausgeben.

+0

Das macht Sinn. Aber ich habe noch nie davon gehört, eine Variable eines unbekannten Datentyps zu behandeln. Wie würde CoCreateInstance mit ifaceptr umgehen, wenn es nicht weiß, um welchen Typ es sich handelt. zweitens ist die Void-Größe beliebig für die Größe des ursprünglichen Datentyps. – numerical25

+0

CoCreateInstance erstellt immer einen Zeiger auf ein COM-Objekt und gibt es über den Parameter 'void **' zurück. Sie sagen ihm, welchen Typ Sie wollen, in Form des Parameters 'IID_ISomeInterface', und Sie sind verantwortlich für die korrekte Verwendung von Typecasts, um' void ** 'in etwas zu verwandeln, das Sie verwenden können. –

+0

'CoCreateInstance()' "weiß", welcher Typ der Ausgabezeiger gemäß der Interface-ID sein soll (dafür ist "IID_ISomeInterface" im Beispiel). Außerdem haben ** alle ** Zeiger die gleiche Größe für eine gegebene Architektur (z.B. sind alle Zeiger auf einem 32-Bit-System 4 Bytes, während alle Zeiger auf einem 64-Bit-System 8 Bytes sind). Es gibt keinen "void" -Typ, aber Sie können "void" -Zeiger haben. Es bedeutet im Grunde einen Zeiger auf einen beliebigen Typ. –

1

Das wandelt &variable in einen void** um (also einen Zeiger auf einen Zeiger auf void).

Zum Beispiel, wenn Sie etwas entlang der Linien von haben

void myFunction(void** arg); 

int* variable; 

Dieser übergibt die Adresse von variable (das ist, was die unary- & tut, ist es die Adresse nimmt) zu myFunction().

3

Es ist ein Zeiger auf einen Zeiger auf eine Variable mit einem nicht angegebenen Typ. Alle Zeiger haben die gleiche Größe, also bedeutet void* nur "einen Zeiger auf etwas, aber ich habe keine Ahnung, was es ist". Ein void** könnte auch ein 2D-Array eines nicht spezifizierten Typs sein.

+0

"* Alle Zeiger haben die gleiche Größe *" ist nicht unbedingt wahr. Aber man könnte richtiger sagen: "Ein Zeiger auf void ist groß genug, um einen Zeiger auf irgendeine Art von Objekt zu speichern". –

7

void* ist ein "Zeiger auf alles". ist eine andere Ebene der Indirektion - "Zeiger auf Zeiger auf alles". Im Grunde übergeben Sie das, wenn Sie zulassen möchten, dass die Funktion einen Zeiger eines beliebigen Typs zurückgibt.

&variable übernimmt die Adresse der Variablen. variable sollte bereits eine Art von einem Zeiger dafür sein, um zu arbeiten, aber es ist wahrscheinlich nicht void * - es könnte sein, sagen int *, so unter seiner Adresse würde in int ** führen. Wenn die Funktion void ** annimmt, müssen Sie auf diesen Typ umwandeln.

(Natürlich muss es tatsächlich ein Objekt des richtigen Typs zurückgeben, sonst Code Aufruf auf der Bahn wird scheitern, wenn er versucht es den falschen Weg zu verwenden.)

+0

ok, also muss die aufrufende Funktion den Typ void als Argument anfordern, damit ich mein Objekt als void ausgeben kann. Aber ich denke, die folgende Frage ist, was hat der Datentyp void zu bieten, die für die Funktion von Vorteil sein wird?Wenn void einen unbekannten Datentyp darstellt, bedeutet dies, dass die Eigenschaften und Werte ebenfalls unbekannt sind. – numerical25

+0

Es ermöglicht Ihnen, die Typprüfung zu umgehen, die normalerweise ausgeführt würde; Sie könnten zum Beispiel eine Funktion haben, die einen Zeiger auf eine Funktion nimmt, und ein Argument, mit dem sie aufgerufen wird, und dann das Ergebnis zurückgeben. Wenn Sie den Typ angeben müssten (z. B. char *, int * usw.), müssten Sie für jeden Argumenttyp eine Funktion haben. Mit void * können Sie die Daten verwenden, ohne sich darum kümmern zu müssen, was die tatsächlichen Typen sind. –

0

Die Variablen ein Zeiger auf etwas von undefiniertem (void) Typ. Der Operator & gibt die Adresse dieser Variablen zurück, so dass Sie jetzt einen Zeiger auf einen Zeiger von etwas haben. Der Zeiger wird also durch Referenz in die Funktion übernommen. Die Funktion hat möglicherweise einen Nebeneffekt, der den von diesem Zeiger referenzierten Speicher ändert. Mit anderen Worten, der Aufruf dieser Funktion könnte das Etwas verändern, auf das der ursprüngliche Zeiger verweist.

1

es Stück für Stück auseinander nehmen ...

myFunction nimmt einen Zeiger auf einen Zeiger vom Typ void (das ist ziemlich viel bedeutet, könnte es zu etwas Punkt). Es könnte so etwas wie folgt lauten:

myFunction(void **something); 

Alles, was Sie übergeben, muss diesen Typ haben. Du nimmst also die Adresse eines Zeigers und wirfst sie mit (void **), um es zu einem leeren Zeiger zu machen. (Im Grunde strippt es von irgendeiner Idee darüber, worauf es hinweist - worüber der Compiler ansonsten winseln könnte.)

Dies bedeutet, dass & Variable die Adresse (& dies tut) eines Zeigers ist - so Variable ist ein Zeiger. Um was? Wer weiß!

Hier ist eine vollständigere Schnipsel, eine Vorstellung davon zu geben, wie das passt zusammen:

#include <stdio.h> 

int myInteger = 1; 
int myOtherInt = 2; 
int *myPointer = &myInteger; 

myFunction(void **something){ 
    *something = &myOtherInt; 
} 

main(){ 
    printf("Address:%p Value:%d\n", myPointer, *myPointer); 
    myFunction((void**)&myPointer); 
    printf("Address:%p Value:%d\n", myPointer, *myPointer); 
} 

Wenn Sie diese kompilieren und ausführen, es diese Art der Ausgabe geben sollte:

Address:0x601020 Value:1 
Address:0x601024 Value:2 

Sie können sehen, dass myFunction den Wert von myPointer geändert hat - was nur möglich war, weil die Adresse des Zeigers übergeben wurde.

+0

Oooo, ok. Also korrigiere mich, wenn ich falsch liege. Ein void-Zeiger soll nur einen beliebigen Datentyp enthalten. Sobald ein bestimmter Datentyp in den void-Zeiger umgewandelt wurde, wird der void-Zeiger zu diesem Datentyp. Und natürlich kann ich keinen void-Zeiger in eine Funktion übergeben, außer die Funktionsanforderung dafür. – numerical25

+0

Ein Zeiger ist nur ein Wert - eine Adresse im Speicher. Sein Typ ist ein Hinweis für den Compiler, auf was er hinweist. Ein Void-Pointer ist so, als würde man dem Compiler sagen, dass man ihm nicht sagen wird, auf welchen Typ der Pointer zeigen könnte. Bei der Übergabe von Parametern müssen Sie immer dem Typ entsprechen, für den die Funktion akzeptiert wird. Wenn also die Funktion eine Lücke haben will ** und Sie ein int ** haben, müssen Sie sie so umwandeln, wie es die Funktion erwartet. –

0
#include <stdio.h> 
#include <iostream> 

int myInteger = 1; 
std::string myOtherInt = "Test"; 
int *myPointer = &myInteger; 

void myFunction(void **something) 
    { 
     *something = &myOtherInt; 
    } 

int main(){ 
    //printf("%d\n", *myPointer); 
    printf("Address:%p Value:%d\n", myPointer, *myPointer); 
    myFunction((void**)&myPointer); 
    printf("Address:%p Value:%d\n", myPointer, *myPointer); 
}