2008-11-20 8 views
15

Párrafo 6.7.3.8 de los estados de especificación C99tipos de matriz constante en C, defecto en estándar?

Si la especificación de un tipo de matriz incluye cuali fi cadores cuali fi cados, el tipo de elemento está calificado, no el tipo de matriz. Si la especificación de un tipo de función incluye cuali fi cadores de tipo, el comportamiento es indefinido.

En el rationale (página lógica 87, página física 94), se proporciona un ejemplo de conversión de un puntero plano a un puntero de matriz (longitud variable).

void g(double *ap, int n) 
{ 
    double (*a)[n] = (double (*)[n]) ap; 
    /* ... */ a[1][2] /* ... */ 
} 

Ciertamente, si la matriz ap no se modifica dentro de la función, que debe ser marcado const, sin embargo el reparto en

void g(const double *ap, int n) 
{ 
    const double (*a)[n] = (const double (*)[n]) ap; 
    /* ... */ 
} 

no conserva el const calificador desde (por 6.7.3.8) se se aplica a los elementos del objetivo en lugar del propio objetivo, que tiene el tipo de matriz double[n]. Esto significa que los compiladores se quejarán correctamente si se les dan los indicadores apropiados (-Wcast-qual para GCC). No hay forma de indicar un tipo de matriz const en C, pero este modelo es muy útil y "correcto". El indicador -Wcast-qual es útil para identificar el uso indebido de los parámetros de la matriz, pero los falsos positivos desalientan su uso. Tenga en cuenta que la indexación a[i][j] es más legible y, con muchos compiladores, produce un mejor código de máquina que ap[i*n+j], ya que el primero permite que parte de la aritmética entera se levante de los bucles internos con menos análisis.

¿Deberían los compiladores tratar esto como un caso especial, alzando efectivamente los calificadores de los elementos al tipo de matriz para determinar si un elenco dado elimina los calificadores o debería modificarse la especificación? La asignación no está definida para los tipos de matriz, por lo tanto, ¿le molestaría a los calificadores aplicar siempre al tipo de matriz en lugar de solo a los elementos, en contraste con 6.7.3.8?

+0

Me enrolla cuando '~ (página lógica N ≡ página física N)'. –

Respuesta

6

Este es un problema conocido que se ha debatido varias veces en los últimos 10 años en comp.std.c. La conclusión es que el caso específico que presentó no es actualmente legal en el Estándar C; necesita eliminar el calificador o abstenerse de usar un puntero a una matriz para referirse a los elementos calificados en la matriz.

Si cree que tiene una buena idea para solucionar el problema, puede publicarlo en news:comp.std.c para su discusión. Si otros acuerdan que es una buena idea, usted u otra persona puede presentar un informe de defectos para cambiar el comportamiento (hay varios miembros del comité que frecuenten comp.std.c, de modo que los comentarios de las personas que potencialmente revisarían el DR ser útil tener antes de archivarlo). Creo que puede haber algunos problemas con su propuesta para que los calificadores afecten a la matriz en sí, pero tendría que pensarlo un poco más.

+0

Gracias, me doy cuenta de que no soy la primera persona en toparse con esto. Cuando busqué comp.std.c, encontré varios casos en los que las personas querían una tarea similar sin un elenco explícito. Con el reparto, creo que el ejemplo es perfectamente seguro y las normas se ajustan, aunque el compilador no lo ve bien. – Jed

+1

C99 agregó varias características para hacer que C sea más atractivo para los números, especialmente VLA y restringir. En lugar del estándar que aborda este caso, sería bueno que los compiladores pudieran determinar que el elenco era realmente seguro. – Jed

+0

Puede ser "seguro" en el sentido de que no funciona como se esperaba con las implementaciones existentes, pero según la forma en que se redacta el estándar hoy, creo que los compiladores son correctos y técnicamente no es un código válido de C. –

0

La situación es incómoda con punteros (es decir, las matrices), pero aquí está mi recuerdo de los detalles:

const double *ap es un puntero a una constante doble;

double *const ap es un puntero constante a un doble;

const double *const ap es un puntero constante a un doble constante;

Así que creo que es posible hacer lo que está pidiendo, aunque no lo he intentado en años: la opción gcc que está utilizando no estaba disponible la última vez que lo hice.

EDIT: Esta respuesta no es correcta para la pregunta - Me voy a preservar los comentarios a continuación, que aclaran el problema para los simples mortales (o desarrolladores oxidados C ...)

+0

Mi C está oxidado, pero ¿por qué 'const double * const ap' en la firma del método no hace exactamente lo que está solicitando? ¿Referencia de matriz constante y referencias de elementos constantes? –

+0

No, las constelaciones del ejemplo se refieren a los elementos, no a los punteros. Una peculiaridad del lenguaje (¿o compilador?) Hace que parezca que el calificador const de los elementos no se conserva, cuando lógicamente se conserva. – finnw

+0

El segundo 'const' es irrelevante ya que no nos importa cambiar el valor del puntero' ap'. Queremos convertir un "puntero a const double" en "puntero en const array of double", esto no se puede expresar en C, por lo que lo convertimos en "puntero a matriz de const double" que activa la advertencia. – Jed

1

solución posible para el C programador (pero no el diseñador del compilador):

gcc con -Wcast-qual no se queja de esto:

void g(const double *ap, int n) 
{ 
    int i; 
    struct box 
    { 
     double a[n]; 
    }; 
    const struct box *s = (const struct box *)ap; 

    for (i=0; i<n; ++i) 
    { 
     doStuffWith(s->a[i]); 
     /* ... */ 
    } 
} 

Incluso si no es muy elegante. El miembro de la matriz posterior a también tiene un significado ligeramente diferente entre C89 y C99, pero al menos se obtiene el efecto deseado.

+0

Realmente se vería como 's [i] .a [j]' que el compilador probablemente podría optimizar de la misma manera que 'a [i] [j]'. Esta solución evita la advertencia, pero agrega una ofuscación significativa, particularmente para las matrices de 4 dimensiones que yo uso. – Jed

Cuestiones relacionadas