El estándar C11 ISO/IEC 9899:2011 (E) establece las siguientes restricciones para asignaciones simples en §6.5.16.1/1:
Se cumplirá uno de los siguientes:
- el operando izquierdo tiene tipo aritmético atómico, calificado o no calificado, y el derecho tiene tipo aritmético;
- el operando izquierdo tiene una versión atómica, calificada o no calificada de una estructura o tipo de unión compatible con el tipo de la derecha;
- el operando izquierdo tiene un tipo de puntero atómico, calificado o no calificado y (considerando el tipo que tendría el operando izquierdo después de la conversión de lvalue) ambos operandos son punteros a versiones calificadas o no calificadas de tipos compatibles, y el tipo al que apunta la izquierda tiene todos los calificativos del tipo señalado por la derecha;
- el operando izquierdo tiene un tipo de puntero atómico, calificado o no calificado y (considerando el tipo que tendría el operando izquierdo después de la conversión de lvalue) un operando es un puntero a un tipo de objeto y el otro es un puntero a una versión calificada o no calificada de nulo, y el tipo señalado por la izquierda tiene todos los calificadores del tipo señalado por la derecha;
- el operando izquierdo es un puntero atómico, calificado o no calificado, y el derecho es una constante de puntero nulo; o
- el operando izquierdo tiene tipo atómico, calificado o no calificado
_Bool
y la derecha es un puntero.
Estoy interesado en el caso en el que ambos lados son punteros a incompatible tipos diferentes de void
. Si entiendo correctamente, esto debería al menos invocar UB, ya que viola esta restricción. Un ejemplo de tipos incompatibles debería ser (según §6.2.7 y §6.7.2) int
y double
.
Por lo tanto, el siguiente programa debería estar en violación:
int main(void) {
int a = 17;
double* p;
p = &a;
(void)p;
}
Tanto gcc como clang advierten sobre “-Wincompatible-pointer-types”, pero no cancelan la compilación (compilación con -std=c11 -Wall -Wextra -pedantic
).
De manera similar, el siguiente programa solo conduce a una advertencia de “-Wint-conversion”, mientras se compila correctamente.
int main(void) {
int a;
double* p;
p = a;
(void)p;
}
Viniendo de C ++, esperaba que cualquiera de esos casos de prueba requiriera un molde para compilar. ¿Hay alguna razón por la cual cualquiera de los programas sería legal para los estándares? O, ¿existen al menos razones históricas significativas para admitir este estilo de código incluso cuando se deshabilitan las entretenidas extensiones GNU C al usar explícitamente -std=c11
en vez de -std=gnu11
?