bitlvl
SR

Vizuelizator rasporeda C struktura i bit polja

Nalepite jednu ili više struct, union, enum ili typedef definicija. Svaka struktura se iscrtava bajt po bajt sa svojim popunjavanjem, za ABI koji izaberete, tačno onako kako bi je rasporedili GCC, Clang ili MSVC. Zatim nalepite heks ispis da vidite vrednosti polja.

Dekodiraj heks ispis u ovu strukturu
Redosled bajtova

Rezultati i poruke ovog alata prikazuju se na engleskom.

Zašto strukture imaju rupe

Svaki skalarni tip ima poravnanje: na većini ABI-ja 4-bajtni int mora da stoji na adresi deljivoj sa 4, 8-bajtni double ili pokazivač na adresi deljivoj sa 8. Kompajler ubacuje popunjavanje (padding) ispred člana da bi dostigao njegovo poravnanje, i na kraju, da bi nizovi strukture držali svaki element poravnatim (poravnanje same strukture je poravnanje njenog najstrože poravnatog člana). struct { char c; int i; } zato ima 8 bajtova, a ne 5, a struct { char a; long b; char c; } ima 24 bajta, dok { long b; char a; char c; } ima 16. Ređanje članova od najvećeg poravnanja ka najmanjem uklanja većinu popunjavanja, što je ono što radi predlog preuređivanja.

Šta se razlikuje između ABI-ja

Tipx86-64 SysVAArch64i386ARM32MSVC x64
long88444
pointer88448
double8, poravnanje 88, poravnanje 88, poravnanje 48, poravnanje 88, poravnanje 8
long longporavnanje 8poravnanje 8poravnanje 4poravnanje 8poravnanje 8
long double16, poravnanje 1616, poravnanje 1612, poravnanje 488
wchar_t44442
pravila za bit poljaItanium: polje se smešta na sledeći bit osim ako bi prešlo prozor od sizeof(type) bajtova; neimenovana polja ne utiču na poravnanje (x86) ili utiču (ARM)svaki niz polja iste veličine dobija sopstvenu jedinicu skladištenja; promena tipa započinje novu jedinicu

Isti izvorni kod zato može da proizvede različite binarne rasporede na različitim platformama, zbog čega strukture koje idu preko mreže ili u datoteke treba da koriste tipove fiksne širine, eksplicitne članove za popunjavanje i static_assert(sizeof(struct x) == 24).

Bit polja

Susedna bit polja se pakuju u jedinicu skladištenja svog deklarisanog tipa. Kod GCC-a i Clanga polje ide na sledeći slobodan bit osim ako bi prelazilo prozor od sizeof(type) bajtova, u kom slučaju se pomera na sledeću granicu poravnanja; polje nulte širine (int :0) prisiljava sledeće polje u novu jedinicu. MSVC dodeljuje novu jedinicu kad god se veličina tipa promeni, pa int a:8; char b:8; zauzima 5 bajtova na MSVC-u, a 2 na GCC-u. Redosled bitova unutar jedinice prati endianness platforme (najmanje značajni bitovi prvi na little-endian), zbog čega su bit polja loš način za opisivanje formata na žici.

packed, aligned i #pragma pack

__attribute__((packed)) uklanja sve popunjavanje (članovi mogu biti neporavnati, što je sporo na x86 i izaziva grešku na nekim ARM konfiguracijama). #pragma pack(n) ograničava poravnanje članova na n bajtova. __attribute__((aligned(n))) i _Alignas(n) povećavaju poravnanje, obično na 16 za SIMD ili 64 za keš liniju. Sve ovo je prikazano u rasporedu.

Pitanja

Koliko je ovo tačno?

Mehanizam je testiran prema clang -fdump-record-layouts za x86-64, i386, AArch64, ARM32 i MSVC x64 na skupu struktura sa bit poljima, pakovanjem, ugnežđenim unijama i poljima nulte širine. GCC i Clang se na ovim ABI-jima međusobno slažu. Za egzotične slučajeve (prekomerno poravnati tipovi u bit poljima, __int128 na 32 bita, vektorski tipovi) proverite sa kompajlerom.

Kako da dobijem prave vrednosti iz svog kompajlera?

clang -Xclang -fdump-record-layouts -c file.c ispisuje svaku strukturu; GCC: kompajlirajte sa -g i pokrenite pahole nad objektnom datotekom, ili koristite offsetof() i sizeof() u malom programu. Dodajte static_assert(offsetof(struct s, x) == 8) da zaključate raspored.

Kaže da je tip nepoznat.

Tipovi iz sistemskih zaglavlja (size_t, uint32_t, time_t i Windows DWORD porodica) su ugrađeni; za sve ostalo je potrebno nalepiti typedef iznad strukture koja ga koristi. Nepoznato ime se tretira kao 4-bajtni int i označava.

Može li da dekodira strukturu iz core dumpa ili paketa?

Nalepite bajtove u odeljak za dekodiranje. Celi brojevi, float brojevi, char, pokazivači, char nizovi i bit polja prikazuju se sa redosledom bajtova koji izaberete; ugnežđene strukture se navode, ali ne razvijaju (izaberite unutrašnju strukturu da je dekodirate zasebno).

Zašto preuređivanje ne pomaže mojoj strukturi?

Ako su članovi već sortirani po poravnanju, ili struktura ima bit polja ili anonimne unije (koje se ne preuređuju automatski), predlog se ne prikazuje. Popunjavanje na kraju je neizbežno kada poravnanje najvećeg člana ne deli zbir veličina.