Extensão Struct em C
Suponha que existam 2 estruturas definidas como:
typedef struct {
T x;
T y;
} A;
typedef struct {
A a;
T z;
} B;
Posso tratar um ponteiro para a estrutura B como um ponteiro para a estrutura A?
Na prática, é confiável / padrão / portátil / invariante do compilador:
B b = {{1,2},3};
A * a = &b;
print(a->x);
print(a->y);
Respostas
C17 6.7.2.1 afirma isso (ênfase minha):
Dentro de um objeto de estrutura, os membros do campo que não são de bits e as unidades nas quais os campos de bits residem têm endereços que aumentam na ordem em que são declarados. Um ponteiro para um objeto de estrutura, adequadamente convertido, aponta para seu membro inicial (ou se esse membro for um campo de bits, então para a unidade na qual ele reside) e vice-versa .
Isso significa que você deve "converter adequadamente" o ponteiro do B bobjeto no tipo de seu primeiro membro. Essa conversão não acontece implicitamente, você deve fazer isso por meio de um elenco explícito:
A * a = (A*)&b;
Fazer isso é bem definido e seguro, conforme a parte citada acima.
Da mesma forma, o compilador não tem permissão para assumir que um ponteiro para Ae um ponteiro para Bnão são apelidos. A regra do tipo efetivo 6.5.7 ("aliasing estrito") oferece uma exceção para este caso:
Um objeto deve ter seu valor armazenado acessado apenas por uma expressão lvalue que possui um dos seguintes tipos:
...
- um tipo de agregado ou união que inclui um dos tipos mencionados acima entre seus membros
Por exemplo, durante a otimização, um compilador que chama a função void func (B* b)não pode assumir que uma variável de linhagem externa extern A a;definida em alguma outra unidade de tradução não foi alterada pela função.