Chcę pobrać część danych wewnątrz niektórych struktur C, aby częściowo je przekształcić/deserializować, zapisując bajty z pamięci na dysk i viceversa.sizeof() część struktury C - sortowanie
Struktury nie są znane z góry, są budowane dynamicznie za pomocą mojego własnego generatora kodu C (jak również kodu, który je serializuje). Pola serializowalne zostaną umieszczone na początku struktury.
Powiedzmy, że mają struct z 4 polami, a pierwsze dwa mają być szeregowane:
typedef struct {
int8_t x1;
int32_t x2; /* 1 + 4 = 5 bytes (if packed) */
int8_t y1;
int32_t y2; /* 1 + 4 +1 + 4 = 10 bytes (if packed) */
} st;
mam zamiar chwycić wskaźnik do zmiennej struct i zapisu/odczytu na n
bajtów, które obejmują te, dwa pierwsze pola (x1, x2
). Nie sądzę, żebym musiał się martwić o wyrównanie/pakowanie, ponieważ nie zamierzam serializacji, aby przetrwać różne kompilacje (oczekuje się, że tylko jeden plik wykonywalny będzie czytać/zapisywać dane). A ponieważ jestem ukierunkowany na szeroki zakres kompilatorów-architektur, nie chcę umieszczać założeń na temat alignment-packing lub specyficznych sztuczek kompilatora.
Następnie muszę policzyć bajty. I nie mogę po prostu zrobić sizeof(st.x1)+sizeof(st.x2)
z powodu dopełnienia-dopełnienia. Tak, mam zamiar odjąć wskazówek, od początku do pierwszej struktury „bez przetrwałego” pola:
st myst;
int partsize = (char*)&myst.y1 - (char*)(&myst);
printf("partial size=%d (total size=%d)\n",partsize,sizeof(myst));
To wydaje się działać. I może być umieszczony w makrze.
(Dla przypomnienia: próbowałem również napisać inne makro, które nie wymaga instancji struktury, coś w rodzaju this, ale nie wydaje się to możliwe tutaj - ale to nie ma znaczenia dla mnie).
Moje pytanie: czy to jest poprawne i bezpieczne? Czy widzisz jakąś pułapkę lub lepsze podejście?
Między innymi: czy standardowe C (i de facto kompilatory) zakładają, że pola structs leżą w pamięci w tej samej kolejności, w jakiej są zdefiniowane w źródle? Prawdopodobnie jest to głupie pytanie, ale chciałbym mieć pewność, ...
UPDATE: Niektóre wnioski z odpowiedzi i moje własne odkrycia:
Wydaje się, że nie ma problemu z moim podejściem . W szczególności C dyktuje, że pola struct nigdy nie zmienią porządku.
Można również (zgodnie z sugestią aswer) policzyć z ostatniego trwałego pola i dodać jego rozmiar:
(char*)&myst.x2 + sizeof(&myst.x2) - (char*)(&myst)
. Byłoby to równoważne, poza tym, że nie zawierałby dopełnienia bajtów (jeśli są obecne) dla ostatniego pola. Bardzo mała przewaga - i bardzo mała wada, w byciu mniej prostą.Ale zaakceptowana odpowiedź, z
offsetof
, wydaje się być lepsza niż moja propozycja. Jest to wyraźna ekspresja i czysty czas kompilacji, nie wymaga instancji struktury. Dalej wydaje się być standardem, dostępnym w każdym kompilatorze. Jeśli nie potrzeba konstruować kompilacji i istnieje instancja dostępnej struktury (jak to jest w moim scenariuszu), oba rozwiązania są w zasadzie równoważne.
Powiązane pytanie: http://stackoverflow.com/questions/2748995/c-struct-memory-layout – payne
Usunąłem tag C++, ponieważ w pobliżu tego pytania nie ma C++. – Puppy