Ich habe in C ein eigenartiges Verhalten gefunden. Betrachten Sie den folgenden Code:
struct s {
int a;
};
struct z {
int a;
struct s b[];
};
int main(void) {
return 0;
}
Es kompiliert ganz gut. Ändern Sie dann die Reihenfolge der Mitglieder von struct z
wie folgt
struct z {
struct s b[];
int a;
};
Und plötzlich bekommen wir den Kompilierungsfehler field has incomplete type 'struct s []'
.
Warum ist das so?
Der Compiler kann nicht berechnen, wie viel Speicher belegt
struct s b[];
wird. Dies bedeutet, dass der Compiler nicht herausfinden kann, wo sich diese Felder befinden, wenn die Struktur Felder enthält.Früher war es (in alten Versionen von C) so, dass (z. B.)
struct s b[];
als Mitglied einer Struktur nicht erlaubt war. Dies machte eine effiziente Speicherverwaltung ärgerlich. Stellen Sie sich als einfaches Beispiel vor, Sie haben eine Struktur, die eine "Name" -String enthält (dies können nur wenige oder viele Zeichen sein). Sie können ein Array mit fester Größe verwenden, das groß genug für den größten Namen ist (was Speicherplatz verschwendet), oder einen Zeiger verwenden und zwei Speicherelemente zuweisen (eines für die Struktur und eines für die Namenszeichenfolge mit variabler Länge). Alternativ können Sie einen Zeiger verwenden und ihn auf zusätzlichen Platz hinter dem Ende der Struktur verweisen lassen, was ungefähr so aussieht:length = strlen(my_string); foo = malloc(sizeof(MYSTRUCTURE) + length + 1); foo->name = (void *)foo + sizeof(MYSTRUCTURE); // Set pointer to extra bytes past end of structure memcpy(foo->name, my_string, length + 1);
Dies war die effizienteste Option; aber es ist auch hässlich und fehleranfällig.
Um dies zu umgehen, haben Compiler nicht standardmäßige Erweiterungen hinzugefügt, um Arrays mit "unbekannter Größe" am Ende der Struktur zuzulassen. Dies machte es für Programmierer etwas einfacher und effizienter (da kein zusätzliches Zeigerelement erforderlich ist). Dies wurde schließlich vom C-Standard übernommen (vielleicht in C99 - ich erinnere mich nicht).
quelle
[]
ist semantisch etwas anders, da ein Compiler die direkte Instanziierung einer Struktur ermöglichen würde, die ein Array mit der Größe Null enthält (obwohl die Verwendung des Arrays UB wäre), während eine FLA oder eine Struktur, die eines enthält, das letzte Element von sein muss eine Struktur.In der Regel spielt die Reihenfolge der Elemente eine Rolle (dh, zwischen den Feldern wird möglicherweise ein Auffüllen eingefügt). In Ihrem speziellen Fall verwenden Sie jedoch ein flexibles Elementarray. Dies ist in C99 - 6.7.2.1.16 standardisiert
Ihr
struct s b[];
Mitglied soll für den Zugriff auf dynamische Heap-Zuordnungen für mehrerestruct s
Elemente verwendet werden.quelle
Der Titel Ihrer Frage lautet "Ist die Reihenfolge der Mitglieder in einer
struct
Angelegenheit?".Das offensichtliche Problem in Ihrem Code hängt mit der Tatsache zusammen, dass Sie
struct
ein flexibles Mitglied enthalten.Hier ist also ein zusätzliches Problem im Zusammenhang mit der allgemeinen Frage der Reihenfolge der Mitglieder in a
struct
:Nehmen Sie zum Beispiel die folgenden zwei Strukturen:
struct s1 { int a; short b; char c; }; struct s2 { char c; short b; int a; };
Die meisten Compiler fügen Auffüllungen hinzu, um jedes Mitglied an einer durch seine Größe teilbaren Adresse auszurichten.
So
struct s2
kann letztendlich kompiliert werden in:struct s2 { char c; char pad1; short b; short pad2; short pad3; int a; };
Dies führt schließlich zu unterschiedlichen Größen für Instanzen von Typen
struct s1
undstruct s2
.quelle
In diesem Fall spielt die Bestellung eine Rolle. Ihr
struct z
enthält ein Array bestehend ausstructs s
. Diesem Array ist jedoch keine Größe zugeordnet, sodass der Compiler nicht weiß, wie der entsprechende Stapelspeicher zugewiesen werden soll, da anschließend ein weiteres Feld von struct (int a
) vorhanden ist. Ein Beispiel dafür, wie es funktionieren würde:struct s { int a; } struct z { struct s b[10]; int a; } int main(void) { return 0; }
Wenn Sie das Array wirklich benötigen, um die Größe zu ändern, ist es am besten, wenn Sie die gesamte Struktur auf dem Heap mit dem Array als Zeiger zuweisen
struct s
und es dann dynamisch neu zuweisen , um der sich ändernden Arraygröße Rechnung zu tragen. Sehen Siemalloc (3)
,realloc 3)
,calloc (3)
, undfree (3)
.quelle