załóżmy mam struct i wyodrębnić przesunięcie do członka:Jak używać `offsetof` do dostępu do pola w standardowy sposób zgodny?
struct A {
int x;
};
size_t xoff = offsetof(A, x);
jak mogę, biorąc pod uwagę wskaźnik do struct A
wyodrębnić element w standardzie zgodnym sposób? Zakładając oczywiście, że mamy poprawną struct A*
i prawidłowe przesunięcie. Jedna próba byłoby zrobić coś takiego:
int getint(struct A* base, size_t off) {
return *(int*)((char*)base + off);
}
Który prawdopodobnie będzie działać, ale należy pamiętać, że na przykład arytmetyka wskaźnik tylko wydają się być zdefiniowany w normie, czy wskaźniki są wskaźnikami o tej samej tablicy (lub jeden obok koniec), nie musi tak być. Technicznie rzecz biorąc, konstrukcja ta zdaje się opierać na niezdefiniowanym zachowaniu.
Innym rozwiązaniem byłoby
int getint(struct A* base, size_t off) {
return *(int*)((uintptr_t)base + off);
}
które również prawdopodobnie będzie działać, ale należy pamiętać, że nie jest wymagane intptr_t
istnieć io ile wiem, arytmetyka na intptr_t
nie potrzebuje, uzyskując prawidłowy wynik (dla przykład Przypominam, że niektóre procesory mają możliwość obsługi adresów wyrównanych bajtowo, co sugerowałoby, że intptr_t
wzrasta w krokach po 8 dla każdego char
w tablicy).
Wygląda na to, że w standardzie jest coś zapomnianego (lub coś, co przeoczyłem).
jestem całkiem pewny aliasing do '*' char i wskaźników, które wskazują na ten sam obiekt (niekoniecznie tablica) jest ważny. Oczekiwanie na autorytatywną odpowiedź. – Quentin
'' (char *) base' może być używane do poruszania się w dowolnym miejscu wewnątrz 'bazy' (i jednego za końcem). Każdy obiekt zachowuje się jak tablica o rozmiarze 1. –
'return * (int *) ((char *) base + off);' może łatwo zawieść, ponieważ dostęp 'int' może być niewyrównany. Na przykład. dostęp 'int' może powodować błąd magistrali na nieparzystym adresie. OP OTOH powiedział "Zakładając ... mamy poprawną strukturę A * i poprawne przesunięcie" – chux