No es un comportamiento indefinido , independientemente de lo que alguien, oficial o no , diga, porque está definido por el estándar. p->s
, excepto cuando se usa como un lvalue, se evalúa como un puntero idéntico a (char *)p + offsetof(struct T, s)
. En particular, este es un char
puntero válido dentro del objeto malloc'd, y hay 100 (o más, dependiendo de las consideraciones de alineación) direcciones sucesivas inmediatamente después de él que también son válidas como char
objetos dentro del objeto asignado. El hecho de que el puntero se haya derivado usando en ->
lugar de agregar explícitamente el desplazamiento al puntero devuelto por malloc
, cast to char *
, es irrelevante.
Técnicamente, si p->s[0]
el elemento único de la char
matriz está dentro de la estructura, los siguientes elementos (por ejemplo, a p->s[1]
través p->s[3]
) probablemente sean bytes de relleno dentro de la estructura, que podrían corromperse si realiza una asignación a la estructura como un todo, pero no si simplemente accede a un individuo miembros, y el resto de los elementos son espacio adicional en el objeto asignado que puede usar libremente como quiera, siempre que obedezca los requisitos de alineación (y char
no tenga requisitos de alineación).
Si le preocupa que la posibilidad de superposición con el acolchado de bytes de la estructura puede ser que de alguna forma de invocación demonios nasales, se podría evitar esta reemplazando la 1
de [1]
con un valor que asegura que no hay relleno al final de la estructura. Una forma simple pero inútil de hacer esto sería crear una estructura con miembros idénticos, excepto sin una matriz al final, y usarla s[sizeof struct that_other_struct];
para la matriz. Entonces, p->s[i]
se define claramente como un elemento de la matriz en la estructura para i<sizeof struct that_other_struct
y como un objeto char en una dirección que sigue al final de la estructura para i>=sizeof struct that_other_struct
.
Editar: en realidad, en el truco anterior para obtener el tamaño correcto, es posible que también deba colocar una unión que contenga cada tipo simple antes de la matriz, para asegurarse de que la matriz en sí comience con una alineación máxima en lugar de en el medio del relleno de algún otro elemento . Una vez más, no creo que nada de esto sea necesario, pero se lo ofrezco al más paranoico de los abogados del lenguaje.
Edición 2: La superposición con bytes de relleno definitivamente no es un problema, debido a otra parte del estándar. C requiere que si dos estructuras coinciden en una subsecuencia inicial de sus elementos, se puede acceder a los elementos iniciales comunes mediante un puntero a cualquier tipo. Como consecuencia, si struct T
se declarara una estructura idéntica a, pero con una matriz final más grande, el elemento s[0]
tendría que coincidir con el elemento s[0]
en struct T
, y la presencia de estos elementos adicionales no podría afectar o verse afectada al acceder a elementos comunes de la estructura más grande. usando un puntero a struct T
.