Extensión de estructura en C
Supongamos que hay 2 estructuras definidas como:
typedef struct {
T x;
T y;
} A;
typedef struct {
A a;
T z;
} B;
¿Puedo tratar un puntero a la estructura B como un puntero a la estructura A?
En la práctica, esto es confiable / estándar / portátil / compilador invariante:
B b = {{1,2},3};
A * a = &b;
print(a->x);
print(a->y);
Respuestas
C17 6.7.2.1 establece esto (el énfasis es mío):
Dentro de un objeto de estructura, los miembros que no son de campo de bits y las unidades en las que residen los campos de bits tienen direcciones que aumentan en el orden en que se declaran. Un puntero a un objeto de estructura, convenientemente convertido, apunta a su miembro inicial (o si ese miembro es un campo de bits, entonces a la unidad en la que reside), y viceversa .
Esto significa que debe "convertir adecuadamente" el puntero del B b
objeto en el tipo de su primer miembro. Esta conversión no ocurre implícitamente, debe hacer esto mediante una conversión explícita:
A * a = (A*)&b;
Hacerlo está bien definido y es seguro, según la parte citada anteriormente.
De manera similar, el compilador no puede asumir que un puntero a A
y un puntero a B
no tienen un alias. La regla del tipo efectivo 6.5.7 ("alias estricto") da una excepción para este caso:
Un objeto tendrá acceso a su valor almacenado solo mediante una expresión lvalue que tenga uno de los siguientes tipos:
...
- un tipo de agregado o unión que incluye uno de los tipos antes mencionados entre sus miembros
Por ejemplo, durante la optimización, un compilador que llama a la función void func (B* b)
no puede asumir que extern A a;
la función no modificó una variable de línea externa definida en alguna otra unidad de traducción.