2010-11-23 4 views
4

Was bedeutet Folgendes?Nullgrößenvektor deklarieren

struct foo 
{ 
... 
char bar[0]; // Zero size??? 
}; 

Ich fragte meine Kollegen und sie sagten mir, es ist das gleiche void* bar wie das Schreiben.

Soweit ich weiß, ist ein C-Zeiger nur eine 4-Byte-Variable (zumindest auf einer 32-Bit-Maschine). Wie kann der Compiler wissen, dass Balken [0] ein Zeiger (und damit 4 Bytes lang) ist? Ist das nur syntaktischer Zucker?

Antwort

5

Ihre Kollegen haben gelogen. (Wahrscheinlich nicht absichtlich, aber nicht böse auf sie oder irgendetwas.)

Dies ist ein flexibles Array-Mitglied, und in C99 wird als char bar[]; geschrieben, und in C89 wurde geschrieben als char bar[1];, und die einige Compiler würde lass dich schreiben als char bar[0];. Grundsätzlich verwenden Sie nur Zeiger auf die Struktur, und ordnen sie alle mit einer Menge von zusätzlichem Platz am Ende:

const size_t i = sizeof("Hello, world!"); 
struct foo *p = malloc(offsetof(struct foo, bar) + i); 
memcpy(p->bar, "Hello, world!", i); 
// initialize other members of p 
printf("%s\n", p->bar); 

Auf diese Weise p->bar speichern eine Zeichenfolge, deren Größe nicht durch eine Array-Deklaration beschränkt, sondern was immer noch alles in der gleichen Zuordnung wie der Rest der struct getan wird (anstatt dass das Mitglied eine char * sein muss und zwei malloc s und zwei free s, um es einzurichten).

+0

erklärt Ah jetzt verstehe ich. Auf diese Weise ist die Strukturinstanz in einem fortlaufenden Speicherbereich enthalten. Wenn Balken ein Zeiger wäre, würde er auf einen anderen Speicherabschnitt zeigen. So erlauben flexible Arrays, die Struktur beispielsweise mit einer einzigen Memcopy zu kopieren. Ich habe diese Struktur im Linux-Kernel gefunden und tatsächlich wird eine einzelne Memcopy verwendet, um vom Kernel-Space in den User-Space zu kopieren. – Emiliano

+1

@happy_emi - Zusätzlich zu einem einzelnen 'memcpy' (was ein großes Plus ist) braucht es auch nur ein einziges' malloc' (was relativ teuer sein kann, vor allem, wenn es sich um ein Objekt handelt, aus dem man viele macht) . –

+0

Natürlich. (Ich meinte übrigens copy_to_user, nicht memcpy. Nur für den Rekord.) – Emiliano

0

Dies sollte ein Compiler-Zeit Fehler sein! Nur dynamisch zugewiesene Arrays können mit der Größe 0 zugewiesen werden.

+0

Einige (faule?) Compiler würden flexible Array-Mitglieder als 'char bar [0] deklarieren lassen;' vor C99 standardisierte die 'char bar [];' -Syntax. Das ist also wahrscheinlich kein Fehler. –

0

Auf ein Array wird auch über Zeiger zugegriffen (Indizes sind implizite Zeiger). Also ich vermute, wenn sie dir das sagen, wird dies wie ein Zeiger interpretiert werden. Da es ein Array der Länge Null ist, wird es wahrscheinlich auf den nächsten Wert zeigen (ich hoffe, dass in dieser Struktur etwas folgt).

Dies ist eine Aufforderung, kein Wissen. :)

Es ist nicht, wie Sie etwas tun würden, obwohl ... Wenn sie einen Zeiger wollen, sollten sie einen Zeiger verwenden. Wenn sie dir nicht sagen können, warum es da ist, sollte es nicht sein.

+0

Ich dachte an ein Label selbst. Aber das Feld wird am Ende der Struktur – Emiliano

3

Chris Antwort ist korrekt, aber ich würde das Objekt wahrscheinlich etwas anders zuweisen.

int n = ...; // number of elements you want 
struct foo *p = malloc(offsetof(struct foo, bar[n])); 

dann über sie iterieren mit

for (int i = 0; i < n; ++i) { 
    p->bar[i] = ...; 
} 

Der entscheidende Punkt ist, dass Chris' Antwort seit sizeof(char)==1 funktioniert, aber für eine andere Art, würden Sie durch sizeof *bar explizit mehrfach haben.

+0

Ich vergesse, wo ich sah die offsetof (struct foo, bar [n]) Trick zuerst, aber +1 für mich zu erinnern. Es ist viel besser als meine Version. –

+0

@Chris, vielleicht [Raymonds Blog] (http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx)? –