Sind flexible Array-Mitglieder wirklich notwendig?

Lesezeit: 5 Minuten

Eine Struktur mit einem flexiblen Array-Mitglied soll anscheinend nicht deklariert, sondern in Verbindung mit einem Zeiger auf diese Struktur verwendet werden. Beim Deklarieren eines flexiblen Array-Mitglieds muss mindestens ein weiteres Mitglied vorhanden sein, und das flexible Array-Mitglied muss das letzte Mitglied in dieser Struktur sein.

Nehmen wir an, ich habe eine, die so aussieht:

struct example{
    int n;
    int flm[]; 
}

Um es dann zu verwenden, muss ich einen Zeiger deklarieren und malloc verwenden, um Speicher für den Inhalt der Struktur zu reservieren.

struct example *ptr = malloc(sizeof(struct example) + 5*sizeof(int)); 

Das heißt, wenn ich meinen Film will[] Array für fünf ganze Zahlen. Dann kann ich meine Struktur einfach so verwenden:

ptr->flm[0] = 1; 

Meine Frage ist, sollte ich nicht stattdessen einfach einen Zeiger verwenden können? Es wäre nicht nur vor C99 kompatibel, sondern ich könnte es mit oder ohne Zeiger auf diese Struktur verwenden. In Anbetracht dessen, dass ich bereits malloc mit dem Film verwenden muss, sollte ich dies nicht einfach tun können?

Betrachten Sie diese neue Definition der Beispielstruktur;

struct example{
    int n; 
    int *notflm; 
}

struct example test = {4, malloc(sizeof(int) * 5)}; 

Ich könnte den Ersatz sogar auf die gleiche Weise wie das flexible Array-Mitglied verwenden:

Würde das auch funktionieren? (Vorausgesetzt obige Beispieldefinition mit notflm)

struct example test; 
test.n = 4; 
notflm = malloc(sizeof(int) * 5); 

  • Mögliches Duplikat von Flexible Array-Mitglieder in C – schlecht?. Flexible Arrays sind Teil von C99; Zeiger sind nicht und können Portabilitätsprobleme haben.

    –Ted Hopp

    1. August 2013 um 18:28 Uhr


  • Der Hauptunterschied besteht darin, dass flexible Array-Mitglieder es Ihnen ermöglichen, die gesamte Struktur in einem zusammenhängenden Block zuzuweisen. Wenn Sie die Struktur kopieren möchten, berechnen Sie einfach ihre Größe und erstellen Sie eine Kopie. Während Sie bei einem Zeiger die Struktur selbst kopieren müssen, kopieren Sie dann auch das innere Array.

    – Drew McGowen

    1. August 2013 um 18:31 Uhr

  • @TedHopp Auf welche denkbare Weise könnten Sie möglicherweise ernsthaft sagen, dass Zeiger nicht Teil von C99 sind?

    – Das ist nicht mein richtiger Name

    5. August 2013 um 17:55 Uhr

  • @ElchononEdelson – Das war schlecht formuliert und sollte in einem sehr engen Kontext interpretiert werden. Ich meinte, dass die Verwendung von Zeigern am Ende von a struct als Methode zur Implementierung flexibler Arrays ist nicht Teil des C99-Standards (und kann Portabilitätsprobleme haben, hauptsächlich aufgrund versteckter Polsterung für die Ausrichtung von Arrays/Zeigern).

    –Ted Hopp

    5. August 2013 um 18:07 Uhr


  • Reden wir hier von verschiedenen Dingen? Um einen Zeiger am Ende einer Struktur als flexibles Array-Mitglied zu verwenden, müssten Sie haben struct foo {int bar; int *ary;} *my; my=malloc(sizeof(struct foo)+10*sizeof(int)); my.ary=(int*)(my+1);, etwa. Das ist natürlich zutiefst dumm. Die andere Sache ist, das letzte Element der Struktur einen Zeiger auf eine andere Stelle sein zu lassen, die ordnungsgemäß mit der Adresse eines ordnungsgemäß zugewiesenen Speicherblocks initialisiert wurde. Dies stellt keine Struktur mit einem flexiblen Array-Mitglied dar, es ist einfach eine andere Technik mit eigenen unterschiedlichen Problemen.

    – Das ist nicht mein richtiger Name

    5. August 2013 um 18:56 Uhr

Zeiger sind keine Arrays. Die grundlegenden Gründe für die Wahl der zu verwendenden Methode sind die gleichen wie immer bei Arrays im Vergleich zu Zeigern. Im speziellen Fall von flexiblen Array-Mitgliedern gibt es hier einige Gründe, warum Sie sie einem Zeiger vorziehen könnten:

  • Reduzierung der Speicheranforderungen. Ein Zeiger vergrößert Ihre Struktur um (normalerweise) 4 oder 8 Bytes, und Sie werden viel mehr Overhead ausgeben, wenn Sie den Speicher, auf den verwiesen wird, separat statt mit einem einzigen Aufruf zuweisen malloc.

  • Verbesserung der Zugriffseffizienz. Ein flexibles Anordnungselement befindet sich in einem konstanten Versatz von der Strukturbasis. Ein Zeiger erfordert eine separate Dereferenzierung. Dies wirkt sich sowohl auf die Anzahl der für den Zugriff erforderlichen Anweisungen als auch auf den Druck aus.

  • Atomarität von Zuweisungserfolg/-misserfolg. Wenn Sie die Struktur und den Speicher, auf den sie zeigen soll, als zwei separate Schritte zuweisen, wird Ihr Code zum Aufräumen in den Fehlerfällen viel hässlicher, da Sie den Fall haben, in dem einer erfolgreich war und der andere fehlschlug. Dies kann mit etwas Zeigerarithmetik vermieden werden, um beide aus demselben herauszuschneiden malloc Anfrage, aber es ist leicht, die Logik falsch zu verstehen und UB aufgrund von Ausrichtungsproblemen aufzurufen.

  • Vermeidung von Deep-Copy. Wenn Sie anstelle eines Zeigers ein flexibles Array verwenden, können Sie einfach memcpy (nicht zuweisen, da die Zuweisung die Länge des flexiblen Arrays nicht kennen kann) kopieren, um die Struktur zu kopieren, anstatt auch die Daten kopieren zu müssen, auf die gezeigt wird, und den Zeiger zu reparieren im neuen Exemplar.

  • Vermeiden der Notwendigkeit für deep-free. Es ist sehr bequem und sauber, nur zu können free ein einzelnes Objekt, anstatt es zu müssen free auch Daten, auf die verwiesen wird. Dies kann auch mit dem „Schneiden eines Singles“ erreicht werden malloc“-Ansatz natürlich, aber flexible Arrays machen es einfacher und weniger fehleranfällig.

  • Sicherlich noch viele weitere Gründe…

  • +1 schöne Liste von Gründen, ich habe nach einer schönen Zusammenfassung der Vorteile für diese Antwort gesucht, aber ich habe nichts wirklich Tolles gefunden, ich werde auch auf diese Antwort verlinken, weil dies besser ist als alles andere, was ich gefunden habe bis jetzt.

    – Shafik Yaghmour

    26. November 2013 um 19:59 Uhr

Benutzeravatar von Sergey L
Sergej L.

Diese Konzepte sind definitiv nicht notwendig, wie Sie selbst betont haben.

Die Unterschiede zwischen den beiden, die Sie demonstriert haben, liegen darin, wo sich Ihre Daten im Speicher befinden.

Im ersten Beispiel mit flexiblem Array befinden sich Ihre Metadaten und das Array selbst im selben Speicherblock und können bei Bedarf als ein Block (Zeiger) verschoben werden.

Im zweiten Beispiel befinden sich Ihre Metadaten auf dem Stack und Ihr Array an anderer Stelle auf dem Heap. Um es zu verschieben/kopieren, müssen Sie nun zwei Speicherblöcke verschieben und den Zeiger in Ihrer Metadatenstruktur aktualisieren.

Im Allgemeinen werden Arrays mit flexibler Größe verwendet, wenn Sie ein Array und seine Metadaten räumlich zusammen im Speicher platzieren müssen.

Ein Beispiel, bei dem dies definitiv nützlich ist, ist beispielsweise das Platzieren eines Arrays mit seinen Metadaten in einer Datei – Sie haben nur einen zusammenhängenden Speicherblock und jedes Mal, wenn Sie ihn laden, wird er (höchstwahrscheinlich) an einem anderen Ort Ihrer VM platziert .

  • Die Felddaten könnten in vielen Fällen unmittelbar nach den Strukturdaten angeordnet sein. Dies würde die Verwendung einer einzigen Zuordnung ermöglichen, Aber Jedes Mal, wenn die Struktur geladen, verschoben oder kopiert wird, wäre es notwendig, den Zeiger zu aktualisieren.

    – Superkatze

    2. August 2013 um 15:11 Uhr

1443780cookie-checkSind flexible Array-Mitglieder wirklich notwendig?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy