Pregunta

He visto una función cuyo prototipo es:

int myfunc(void** ppt)

Esta función se llama en un archivo C como     a = myfunc (mystruct ** var1);

donde mystruct es typedef para una de las estructuras que tenemos.

Esto funciona sin errores de compilación en MSVC6.0, pero cuando lo compilo con algún otro compilador de C, se produce un error en el lugar donde se llama a esta función con un mensaje de error:

El argumento de tipo mystruct ** es incompatible con el parámetro de tipo void **

El argumento de myfunc () se mantiene como nulo ** porque parece ser un tipo genérico de función malloc que se llama con varios tipos de variables de estructura para la asignación de memoria

  1. ¿Hay algún tipo como void ** permitido en el estándar C / cualquier compilador de C?
  2. ¿Cómo soluciono esto? [Intenté enviar el argumento de llamada de función a mystruct ** , pero no funcionó]

-AD

¿Fue útil?

Solución

void ** es válido pero, en función de su mensaje de error, es probable que tenga que emitir el argumento explícitamente de la siguiente manera:

mystruct **var1;
x = myfunc ((void**) var1);

Esto se debe a que la función myfunc espera el tipo void ** . Si bien void * se puede convertir implícitamente a cualquier otro puntero, eso no es así para el puntero doble, debe hacerlo explícitamente.

Otros consejos

Las Preguntas frecuentes de comp.lang.c abordan este problema en detalle en Pregunta 4.9 . En resumen, dicen que no es estrictamente portátil lanzar un puntero arbitrario a un void ** ; continúan explicando que "un código como este puede funcionar y a veces se recomienda, pero se basa en que todos los tipos de punteros tienen la misma representación interna (que es común, pero no universal)". Continúan explicando que " cualquier valor void ** con el que juegue debe ser la dirección de un valor void * real en alguna parte; conversiones como (void **) & amp; dp , aunque pueden cerrar el compilador, no son portables (y puede que ni siquiera hagan lo que quieres). "

Por lo tanto, puede lograr de manera segura / portátil el comportamiento deseado con un código como:

some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);

Hay una razón por la cual el compilador no puede transmitir automáticamente desde mystruct ** a void ** .

Considere el siguiente código:

void stupid(struct mystruct **a, struct myotherstruct **b)
{
    void **x = (void **)a;
    *x = *b;
}

El compilador no se quejará de la conversión implícita de myotherstruct * a void * en la línea * x = * b , aunque esa línea intenta colocar un puntero a un myotherstruct en un lugar donde solo se deben colocar los punteros a mystruct .

El error está de hecho en la línea anterior, que está convirtiendo " un puntero a un lugar donde los punteros a mystruct se pueden poner " a "un puntero a un lugar donde se pueden poner punteros a cualquier cosa . Esto es la razón por la que no hay un elenco implícito. Por supuesto, cuando utiliza una conversión explícita, el compilador asume que sabe lo que está haciendo.

Esta pregunta es un poco confusa. Pero sí, void ** es ciertamente C legal y válido, y significa "puntero a puntero a void " como se esperaba.

No estoy seguro acerca de su ejemplo de una llamada, los argumentos (" mystruct ** var1 ") no tienen sentido. Si var1 es de tipo mystruct ** , la llamada debería leer a = func (var1); , esto podría ser un error tipográfico.

La conversión debería funcionar, pero debe realizar la conversión a void ** , ya que eso es lo que la función espera.

Por más sucio que parezca: a veces no puedes resolver un problema sin usar void **.

Sí, void ** es perfectamente aceptable y bastante útil en ciertas circunstancias. También considere que dada la declaración void ** foo y void * bar , el compilador sabrá el tamaño del objeto apuntado por foo (apunta a un puntero, y todos los punteros son del mismo tamaño, excepto en algunas plataformas antiguas de las que no debería preocuparse, pero no sabrá el tamaño del objeto apuntado por barra (podría apuntar a un objeto de cualquier tamaño). Por lo tanto, puede realizar de forma segura la aritmética de punteros en los puntos void ** pero no en los puntos void * . Primero debes lanzarlos a otra cosa, como un char * . GCC le permitirá pretender que void * y char * son equivalentes, cada uno apuntando a un objeto de un solo byte de tamaño, pero esto no es estándar ni portátil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top