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 s
objetos (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 o1
cuá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->b
simplemente 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 int
y short
no dos int
s?
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.