Rozszerzenie Struct w C
Załóżmy, że istnieją dwie zdefiniowane reklamy, takie jak:
typedef struct {
T x;
T y;
} A;
typedef struct {
A a;
T z;
} B;
Czy mogę traktować wskaźnik do struktury B jako wskaźnik do struktury A?
W praktyce jest to niezawodny / standardowy / przenośny / niezmienny przez kompilator:
B b = {{1,2},3};
A * a = &b;
print(a->x);
print(a->y);
Odpowiedzi
C17 6.7.2.1 stwierdza to (wyróżnienie moje):
W obrębie obiektu strukturalnego elementy składowe niebędące polami bitowymi i jednostki, w których znajdują się pola bitowe, mają adresy, które rosną w kolejności, w jakiej są deklarowane. Wskaźnik do obiektu struktury, odpowiednio przekonwertowany, wskazuje na jego początkowy element członkowski (lub jeśli ten element jest polem bitowym, to na jednostkę, w której się znajduje) i odwrotnie .
Oznacza to, że musisz „odpowiednio przekonwertować” wskaźnik B bobiektu na typ jego pierwszego elementu. Ta konwersja nie zachodzi niejawnie, musisz to zrobić za pomocą jawnego rzutowania:
A * a = (A*)&b;
Takie postępowanie jest dobrze zdefiniowane i bezpieczne, zgodnie z cytowaną częścią powyżej.
Podobnie, kompilator nie może zakładać, że wskaźnik do Ai wskaźnik do Bnie mają aliasu. Reguła efektywnego typu 6.5.7 („ścisłe aliasing”) stanowi wyjątek w tym przypadku:
Obiekt ma dostęp do swojej przechowywanej wartości tylko za pomocą wyrażenia l-wartości, które ma jeden z następujących typów:
...
- agregat lub typ związku, który obejmuje jeden z wyżej wymienionych typów wśród swoich członków
Na przykład podczas optymalizacji kompilator wywołujący funkcję void func (B* b)nie może założyć, że zewnętrzna zmienna liniowa extern A a;zdefiniowana w innej jednostce translacji nie została zmieniona przez funkcję.