Matriz dinámica de estructuras y función llamada f (const struct_type * const data )

El siguiente código advierte sobre el tipo incompatible. ¿Cuál es la forma correcta de resolver este código?

Gracias

typedef struct a_struct struct_type; void f(const struct_type *const data[], unsigned n); void test(unsigned n) { struct_type **v; assert(n); v = malloc(n * sizeof(struct_type *)); /* fill v with new struct_type (with a malloc per entry) */ f(v, n); <- WARN on v } 

La razón por la que el comstackdor se queja es la primera const en la statement de f .

Intenta usar

 void f(struct_type *const data[], unsigned n); /*...*/ f( v, n ); 

y no recibirá la misma advertencia. Alternativamente, puedes lanzar v cuando llamas f

 void f(const struct_type *const data[], unsigned n); /*...*/ f( (const struct_type * const *) v, n ); 

Esto es un poco contrario a la intuición, pero en C, no puede pasar un pointer-to-pointer-to-nonconst para un pointer-to-pointer-to-const . Hicieron una excepción especial para permitirle pasar un pointer-to-nonconst para un pointer-to-const .

Aquí hay una pregunta de preguntas frecuentes “¿Por qué no puedo pasar un char ** a una función que espera un const char ** ?” :

Puede utilizar un pointer-to-T (para cualquier tipo T ) donde se espera un pointer-to-const-T . Sin embargo, la regla (una excepción explícita) que permite ligeras discrepancias en los tipos de punteros calificados no se aplica recursivamente, sino solo en el nivel superior. ( const char ** es pointer-to-pointer-to-const-char , y la excepción, por lo tanto, no se aplica).

La razón por la que no puede asignar un valor char ** a un puntero const char ** es algo oscura. Dado que el calificador const existe, el comstackdor desea ayudarlo a cumplir sus promesas de no modificar los valores const . Es por eso que puede asignar un char * a un const char * , pero no al revés: es claramente seguro agregar constness a un simple puntero, pero sería peligroso quitarlo. Sin embargo, suponga que realizó las siguientes series de tareas más complicadas:

 const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */ 

En la línea 3, asignamos un char ** a un const char ** . (El comstackdor debe quejarse.) En la línea 4, asignamos un const char * a un const char * ; Esto es claramente legal. En la línea 5, modificamos a qué apunta un char * : se supone que esto es legal. Sin embargo, p1 termina apuntando a c, que es const . Esto ocurrió en la línea 4, porque * p2 era realmente p1. Esto se configuró en la línea 3, que es una asignación de un formulario que no está permitido, y esto es exactamente por qué la línea 3 no está permitida.

Asignar un char ** a un const char ** (como en la línea 3, y en la pregunta original) no es inmediatamente peligroso. Pero establece una situación en la que la promesa de p2 (que el valor apuntado en última instancia no se modificará) no se puede mantener.

(C ++ tiene reglas más complicadas para asignar punteros const calificados que le permiten realizar más tipos de asignaciones sin incurrir en advertencias, pero aún así protegen contra bashs involuntarios de modificar los valores de const . C ++ aún no permitiría asignar un char ** a un const char ** , pero te dejaría salirte con la asignación de un char ** a un const char * const *.)

En C, si debe asignar o pasar punteros que tengan discrepancias en el calificador en un nivel distinto del primer direccionamiento indirecto, debe usar conversiones explícitas (por ejemplo, ( const char ** ) en este caso), aunque como siempre, la necesidad de tal El reparto puede indicar un problema más profundo que el reparto realmente no resuelve.

Referencias: ISO Sec. 6.1.2.6, sec. 6.3.16.1, sec. 6.5.3 H&S Sec. 7.9.1 pp. 221-2

Vea si esto funcionaría para usted:

 f(struct_type *data); void test(unsigned n) { struct_type *v = malloc(n * sizeof(struct_type *)); f(v); } 

Por favor, hágamelo saber cómo le va.

Editado basado en la respuesta de Rampion. El problema está en la doble const en la statement de f ().

Código con la advertencia:

 struct_type ** v; v = (struct_type **)malloc(10 * sizeof(struct_type *)); f(v); 

Esto se comstack sin previo aviso:

 const struct_type *const* v; v = (const struct_type **)malloc(10 * sizeof(struct_type *)); f(v); 

f espera obtener como entrada una matriz de punteros (const struct_type * []). Pasas un puntero a un puntero de estructura (const struct_type **).

Lo mejor que puedes hacer, IMO, es cambiar la firma de f a:

 void f(const struct_type *const* data); 

¿Por qué necesitas pasar matrices como argumentos a funciones?