Extensión de estructura en C

Aug 21 2020

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

3 Lundin Aug 21 2020 at 08:19

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 bobjeto 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 Ay un puntero a Bno 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.