Considere la siguiente estructura:
struct s {
int a, b;
};
Típicamente 1 , esta estructura tendrá tamaño 8 y alineación 4.
¿Qué pasa si creamos dos struct sobjetos (más precisamente, escribimos en el almacenamiento asignado dos de estos objetos), con el segundo objeto superpuesto al primero?
char *storage = malloc(3 * sizeof(struct s));
struct s *o1 = (struct s *)storage; // offset 0
struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4
// now, o2 points half way into o1
*o1 = (struct s){1, 2};
*o2 = (struct s){3, 4};
printf("o2.a=%d\n", o2->a);
printf("o2.b=%d\n", o2->b);
printf("o1.a=%d\n", o1->a);
printf("o1.b=%d\n", o1->b);
¿Hay algo sobre este programa de comportamiento indefinido? Si es así, ¿dónde queda indefinido? Si no es UB, ¿se garantiza que siempre imprima lo siguiente?
o2.a=3
o2.b=4
o1.a=1
o1.b=3
En particular, quiero saber qué sucede con el objeto señalado por o1cuándo o2, que se superpone, está escrito. ¿Todavía está permitido acceder a la parte no ocultada ( o1->a)? ¿Acceder a la parte con capa es o1->bsimplemente lo mismo que acceder o2->a?
¿Cómo se aplica el tipo efectivo aquí? Las reglas son lo suficientemente claras cuando habla de objetos no superpuestos y punteros que apuntan a la misma ubicación que la última tienda, pero cuando comienza a hablar sobre el tipo efectivo de porciones de objetos u objetos superpuestos, es menos claro.
¿Cambiaría algo si la segunda escritura fuera de un tipo diferente? Si los miembros fueran decir inty shortno dos ints?
Aquí hay un godbolt si quieres jugar con él allí.
1 Esta respuesta se aplica a plataformas donde este no es el caso también: por ejemplo, algunas pueden tener tamaño 4 y alineación 2. En una plataforma donde el tamaño y la alineación son las mismas, esta pregunta no se aplicaría ya que los objetos alineados y superpuestos ser imposible, pero no estoy seguro de si hay alguna plataforma como esa.