2010-05-31 18 views
6

Lo buscaría, pero sinceramente no sabría por dónde empezar porque no sé cómo se llama. He visto variables pasadas a las funciones de esta manera:¿Qué significa (vacío **) en C?

myFunction((void**)&variable); 

que confunde a los diablos de mí Porque todos los que le resulta familiar para mí; Nunca los había visto armarse así antes.

¿Qué significa? Soy un principiante así que cuanto menos jerga, mejor, ¡gracias!

Respuesta

4

Es un molde para un puntero a un void puntero.

Esto se ve bastante a menudo con funciones como CoCreateInstance() en sistemas Windows.

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

El elenco convierte el puntero a un puntero ISomeInterface en un puntero a un puntero void modo que CoCreateInstance() puede establecer ifaceptr a un valor válido.

Dado que es un puntero a un puntero void, la función puede generar punteros de cualquier tipo, dependiendo de la ID de la interfaz (como IID_ISomeInterface).

+0

Eso tiene sentido. Pero nunca escuché sobre manejar una variable de un tipo de datos desconocido. ¿Cómo manejaría CoCreateInstance ifaceptr, si no sabe de qué tipo es? en segundo lugar, es el tamaño del vacío arbitrario para el tamaño del tipo de datos original. – numerical25

+0

CoCreateInstance siempre crea un puntero a un objeto COM y lo devuelve a través del parámetro 'void **'. Usted le dice qué tipo desea, en forma del parámetro 'IID_ISomeInterface', y usted es responsable de usar typecasts correctamente para convertir' void ** 'en algo que pueda usar. –

+0

'CoCreateInstance()' "sabe" qué tipo debe ser el puntero de salida según la ID de la interfaz (para eso es 'IID_ISomeInterface' en el ejemplo). Además, ** todos los punteros ** tienen el mismo tamaño para una arquitectura determinada (por ejemplo, todos los punteros en un sistema de 32 bits son 4 bytes, mientras que todos los punteros en un sistema de 64 bits son 8 bytes). No existe el tipo 'void', pero puede tener punteros' void'. Básicamente significa un puntero a cualquier tipo. –

1

que proyecta &variable a un void** (es decir, un puntero a un puntero a void).

Por ejemplo, si tiene algo en la línea de

void myFunction(void** arg); 

int* variable; 

Esto pasa la dirección de variable (eso es lo que la hace unary- &, toma la dirección) a myFunction().

3

Puntero a un puntero a una variable con un tipo no especificado. Todos los punteros son del mismo tamaño, por lo que void* solo significa "un puntero a algo pero no tengo idea de qué se trata". Un void** también podría ser una matriz 2D de tipo no especificado.

+0

"* Todos los punteros son del mismo tamaño *" no es necesariamente cierto. Pero podría decir más correctamente: "Un puntero al vacío es lo suficientemente grande como para almacenar un puntero a cualquier tipo de objeto". –

7

void* es un "puntero a cualquier cosa". void ** es otro nivel de direccionamiento indirecto - "puntero a puntero a cualquier cosa". Básicamente, pasa eso cuando desea permitir que la función devuelva un puntero de cualquier tipo.

&variable toma la dirección de la variable. variable ya debería ser una especie de puntero para que funcione, pero probablemente no sea void * - podría ser, digamos int *, por lo que tomar su dirección resultaría en int **. Si la función toma void **, entonces necesita convertir a ese tipo.

(Por supuesto, tiene que volver realidad un objeto del tipo correcto, de lo contrario código de llamada fracasará por la pista cuando se trata de utilizar de la manera equivocada.)

+0

ok, así que la función de llamada tiene que solicitar el tipo nulo como argumento para que yo pueda convertir mi objeto en nulo. Pero supongo que la pregunta de seguimiento es ¿qué tiene que ofrecer el tipo de datos vacío que será beneficioso para la función?Si void representa un tipo de datos desconocido, esto significa que las propiedades y valores también son desconocidos. – numerical25

+0

Le permite evitar la verificación de tipo que normalmente se llevaría a cabo; podría (por ejemplo) tener una función que toma un puntero a una función y un argumento para invocarla, luego devuelve el resultado. Si tuviera que especificar el tipo (por ejemplo, char *, int *, etc.), debería tener una función para cada tipo de argumento; usando void * puede usar los datos sin importar cuáles son los tipos reales. –

0

la variable es un puntero a algo de tipo indefinido (vacío). El operador & devuelve la dirección de esa variable, por lo que ahora tiene un puntero a un puntero de algo. Por lo tanto, el puntero se pasa a la función por referencia. La función puede tener un efecto secundario que cambia la memoria a la que hace referencia ese puntero. En otras palabras, llamar a esta función podría cambiar algo a lo que hace referencia el puntero original.

1

desmontarlo pieza por pieza ...

myFunction toma un puntero a un puntero de tipo void (que más o menos significa que podría apuntar a cualquier cosa). Podría declararse algo como esto:

myFunction(void **something); 

Todo lo que usted pase debe tener ese tipo. Entonces tomas la dirección de un puntero y lo lanzas con (void **) para que sea un puntero vacío. (Básicamente despojarla de cualquier idea acerca de lo que apunta -., Que el compilador podría quejarse de lo contrario)

Esto significa que & variable es la dirección (& hace esto) de un puntero - tan variable es un puntero. ¿A qué? ¡Quién sabe!

Aquí hay un fragmento más completa, para dar una idea de cómo esto encaja:

#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); 
} 

Si compilar y ejecutar esto, se debe dar a este tipo de salida:

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

Puede ver que myFunction cambió el valor de myPointer, lo que solo pudo hacer porque se pasó la dirección del puntero.

+0

Oooo, ok. Entonces corrígeme si estoy equivocado. Un puntero de vacío solo está destinado a contener cualquier tipo de tipo de datos. una vez que un tipo de datos específico se convierte en el puntero de vacío, entonces el puntero de vacío pasa a ser de ese tipo de datos. y por supuesto, no puedo pasar un puntero vacío a una función a menos que la función lo solicite. – numerical25

+0

Un puntero es solo un valor: una dirección en la memoria. Su tipo es una indicación para el compilador de qué tipo de cosas apunta. Un puntero de vacío es como decirle al compilador que no le dirá a qué tipo apunta el puntero. Al pasar parámetros, siempre debe coincidir con el tipo que la función está declarada para aceptar. Entonces, si la función quiere un vacío ** y usted tiene un int **, debe convertirlo para que sea lo que espera la función. –

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); 
}