Frage Wie kann diese Struktur eine Größe von == 0 haben?


Es gibt einen alten Post, der nach einem Konstrukt fragt sizeof würde zurückkehren 0. Es gibt einige Highscore-Antworten von Nutzern mit hoher Reputation, die sagen, dass nach dem Standard kein Typ oder eine Variable die Größe 0 haben kann. Und ich stimme zu 100% damit überein.

Wie auch immer, es gibt diese neue Antwort was präsentiert diese Lösung:

struct ZeroMemory {
    int *a[0];
};

Ich wollte gerade abstimmen und kommentieren, aber die Zeit, die ich hier verbracht habe, hat mich gelehrt, auch die Dinge zu überprüfen, die mir zu 100% sicher sind. Also ... zu meiner Überraschung beides gcc und clang zeigen die gleichen Ergebnisse: sizeof(ZeroMemory) == 0. Mehr noch, die Größe einer Variablen ist 0:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...

Waaaaaa ...?

Godbolt-Verbindung

Wie ist das möglich?


75
2017-11-17 14:14


Ursprung


Antworten:


Bevor C genormt wurde, hätten viele Compiler keine Schwierigkeiten gehabt, mit Nulltypen umzugehen, solange der Code niemals versuchte, einen Zeiger von einem anderen auf einen Nulltyp zu subtrahieren. Solche Typen waren nützlich, und ihre Unterstützung war einfacher und billiger als sie zu verbieten. Andere Compiler entschieden sich jedoch dafür, solche Typen zu verbieten, und einige statische Behauptungscodes konnten sich auf die Tatsache verlassen, dass sie quietschen würden, wenn der Code versuchte, ein Array von null Größe zu erstellen. Die Autoren des Standards standen vor der Wahl:

  1. Erlauben Compilern, auch Deklarationen von Array-Arrays der Größe null zu akzeptieren in den Fällen, in denen der Zweck solcher Erklärungen darin bestünde, a Diagnose und Abbruch der Kompilierung, und erfordern, dass alle Compiler akzeptieren solche Erklärungen (wenn auch nicht unbedingt stillschweigend) große Objekte.

  2. Erlauben Compilern, auch Deklarationen von Array-Arrays der Größe null zu akzeptieren in den Fällen, in denen der Zweck solcher Erklärungen darin bestünde, a Diagnose und Abbruchkompilierung, und ermöglichen Compiler, auf solche zu stoßen Deklarationen, um entweder die Kompilierung abzubrechen oder sie in ihrer Freizeit fortzusetzen.

  3. Erfordern, dass Implementierungen eine Diagnose ausgeben, wenn Code a erklärt Zero-Size-Array, aber dann können Implementierungen entweder abbrechen Kompilierung oder Fortsetzung (mit welcher Semantik, die sie für richtig halten) bei ihre Freizeit.

Die Autoren des Standards entschieden sich für # 3. Folglich werden Zero-Size-Array-Deklarationen vom Standard "extension" betrachtet, obwohl solche Konstrukte weitgehend unterstützt wurden, bevor der Standard sie verbot.

Der C ++ - Standard ermöglicht das Vorhandensein leerer Objekte. Um jedoch die Adressen leerer Objekte als Token verwendbar zu machen, müssen sie eine Mindestgröße von 1 haben. Für ein Objekt, für das keine Elemente eine Größe von 1 haben 0 würde somit den Standard verletzen. Wenn ein Objekt jedoch Elemente mit einer Größe von null enthält, stellt der C ++ - Standard keine Anforderungen an die Verarbeitung, außer dass ein Programm, das eine solche Deklaration enthält, eine Diagnose auslösen muss. Da der meiste Code, der solche Deklarationen verwendet, erwartet, dass die resultierenden Objekte die Größe Null haben, ist das nützlichste Verhalten für Compiler, die solchen Code erhalten,, sie so zu behandeln.


49
2017-11-17 18:18



Wie von Jarod42Zero-Size-Arrays sind nicht Standard-C ++, sondern GCC- und Clang-Erweiterungen.

Hinzufügen -pedantic produziert diese Warnung:

5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
    int *a[0];
           ^

Das vergesse ich immer std=c++XX (Anstatt von std=gnu++XX) deaktiviert nicht alle Erweiterungen.

Dies erklärt immer noch nicht die sizeof Verhalten. Aber zumindest wissen wir, dass es kein Standard ist ...


39
2017-11-17 14:19



In C ++ ist ein Array der Größe null unzulässig.

ISO / IEC 14882: 2003 8.3.4 / 1:

[..] Wenn die konstanter Ausdruck (5.19) ist vorhanden, es muss ein ganzzahliger konstanter Ausdruck sein und sein Wert muss größer als Null sein. Der konstante Ausdruck gibt die Grenze (Anzahl der Elemente) des Arrays an. Wenn der Wert des konstanten Ausdrucks ist N, hat das Array N Elemente nummeriert 0 zu N-1und der Typ der Kennung von D ist "Abgeleitete-Deklarator-Typ-Liste Anordnung von N T ". [..]

g ++ benötigt das -pedantic Flag, um eine Warnung für ein Array von null Größe zu geben.


17
2017-11-17 14:28



Zero-Length-Arrays sind eine Erweiterung von GCC und Clang. Bewirbt sich sizeof zu Arrays null Länge wird zu Null ausgewertet.

Eine C ++ - Klasse (leer) kann keine Größe haben 0, aber beachte das die Klasse ZeroMemory ist nicht leer. Es hat ein benanntes Mitglied mit der Größe 0 und anwenden sizeof wird Null zurückgeben.


4
2017-11-17 16:16