c struct unions aliasing

Excepción a la regla de alias estricto en C de 6.5.2.3 Estructura y miembros del sindicato



unions aliasing (1)

El punto más importante es que su cambio (moviendo la unión hacia arriba) no está cambiando la definición de la función foo en absoluto. Sigue siendo una función que recibe punteros no relacionados. En su ejemplo, los punteros pasados ​​están relacionados, mientras que en otros lugares esto podría ser diferente. El objetivo del compilador es servir al caso más general. El cuerpo de la función es diferente después del cambio y no está claro por qué.

La pregunta que hace es acerca de cómo se implementa la optimización cuidadosa en su compilador particular para ciertas teclas de línea de comando. No tiene nada que ver con el diseño de la memoria. En un compilador correcto, el resultado debería ser el mismo. El compilador debe manejar el caso cuando 2 punteros diferentes apuntan al mismo lugar en la memoria.

Cita del estándar C99:

6.5.2.3

5 Se hace una garantía especial para simplificar el uso de las uniones: si una unión contiene varias estructuras que comparten una secuencia inicial común (ver a continuación), y si el objeto de unión contiene actualmente una de estas estructuras, se permite inspeccionar el parte inicial común de cualquiera de ellos en cualquier lugar donde sea visible una declaración del tipo completo de la unión. Dos estructuras comparten una secuencia inicial común si los miembros correspondientes tienen tipos compatibles (y, para los campos de bits, los mismos anchos) para una secuencia de uno o más miembros iniciales.

Hay un ejemplo para este caso:

// The following code is not a valid fragment because // the union type is not visible within the function f. struct t1 { int m; }; struct t2 { int m; }; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union { struct t1 s1; struct t2 s2; } u; /* ... */ return f(&u.s1, &u.s2); }

He agregado algunos cambios:

#include <stdio.h> struct t1 { int m; }; struct t2 { int m; }; union u { struct t1 s1; struct t2 s2; }; int foo(struct t1 *p1, struct t2 *p2) { if (p1->m) p2->m = 2; return p1->m; } int main(void) { union u u; u.s1.m = 1; printf("%d/n", foo(&u.s1, &u.s2)); }

Como puede ver, he movido la declaración de unión fuera de modo que sería visible en foo (). De acuerdo con el comentario de la norma, esto debería haber hecho que mi código sea correcto, pero parece que el alias estricto todavía rompe este código para clang 3.4 y gcc 4.8.2.

Salida con -O0:

2

Salida con -O2:

1

para ambos compiladores.

Entonces mi pregunta es:

¿Realmente C se basa en la declaración del sindicato para decidir si algunas estructuras son una excepción a la regla de aliasing estricta? O ambos gcc / clang tienen un error?

Me parece realmente malo, porque incluso si la función y la unión se declaran en el mismo encabezado, esto no garantiza que la unión sea visible en la unidad de traducción con el cuerpo de la función.