Są to różne formy tak zwanego "strukturalnego hacka", omówione w pytaniu 2.6 z comp.lang.c FAQ.
Definiowanie tablicy wielkości 0 jest w rzeczywistości niezgodne z literą C i obowiązuje od 1989 r. Standard ANSI. Niektóre kompilatory zezwalają na to jako rozszerzenie, ale poleganie na tym prowadzi do nieprzenośności kodu.
Bardziej przenośne sposobem realizacji tego celu jest użyć tablicę o długości 1, na przykład:
struct foo {
size_t len;
char str[1];
};
Można przydzielić więcej niż sizeof (struct foo)
bajtów, przy użyciu len
śledzić przydzielonego rozmiaru, a następnie dostęp do str[N]
, aby uzyskać N-ty element tablicy. Ponieważ kompilatory języka C zwykle nie sprawdzają granic, to na ogół "działają". Ale, ściśle rzecz biorąc, zachowanie jest niezdefiniowane.
Norma ISO 1999 dodano funkcję o nazwie „elastyczne członkowie array”, mającą na celu zastąpienie tego wykorzystania:
struct foo {
size_t len;
char str[];
};
można sobie z nich w ten sam sposób, jak w starszym struct siekać, ale zachowanie jest dobrze zdefiniowane. Ale sam musisz zrobić całą księgowość; sizeof (struct foo)
nadal nie zawiera wielkości tablicy, na przykład.
Można oczywiście użyć wskaźnika zamiast:
struct bar {
size_t len;
char *ptr;
};
I to jest doskonale dobre podejście, ale ma różne semantykę. Główną zaletą "struct hack" lub elastycznych elementów macierzowych jest to, że tablica jest alokowana w sposób przylegający do reszty struktury, i możesz skopiować tablicę wraz ze strukturą przy użyciu memcpy
(o ile cel został odpowiednio przydzielone). Tablica jest przydzielana osobno - co może, ale nie musi być dokładnie tym, czego potrzebujesz.
Proszę podać przykład. – Arafangion
Wyjaśnienie dotyczące struktur. Istnieją trzy przypadki: 'lastMemberOfArray []' w C90, 'lastMemberOfArray []' w C99 i 'lastMemberOfArray [0]' w niestandardowym GNU Goo. W przypadku C90 jest to brudny hack polegający na nieokreślonym zachowaniu. Może pojawić się problem, jeśli na końcu struktury znajdują się bajty o strukturze struct padding. C99 naprawił to i stworzył typ _flexible array member_, który działa w ten sam sposób, ale z dobrze zdefiniowanym zachowaniem. I na koniec, niestandardowe GNU pozwala na tworzenie macierzy o zerowym rozmiarze w tym samym celu. Kompilacja w standardzie z '-std = c99 -pedantic-errors' i' [0] 'nie będzie się kompilować. – Lundin
@ Pierwszy przykład Lundina powinien być "' lastMemberOfArray [1] 'w C90". Prosta literówka, dodając ją tylko dla tych, którzy nie pamiętają. –