Wie groß ist eine Aufzählung in C?


Beste Antwort

Ein sehr heikles Rätsel, wenn Strukturversätze über Maschinengrenzen oder Netzwerkprotokolle hinweg abgeglichen werden müssen . Die Spezifikation besagt, dass die Größe das Minimum sein muss, das erforderlich ist, um den größten Wert darzustellen, den es annehmen kann. So benötigt beispielsweise eine typische Zustandsmaschinen-Zustandsaufzählung möglicherweise nur ein Byte.

Es gibt nur drei Möglichkeiten, die Größe von AFAIK zu steuern:

Einige (aber nicht alle) Compiler haben Ein Compiler-Schalter erzwingt die Größe entweder auf sizeof (int) oder auf 32 Bit. Die Switch-Syntax ist zwischen MSC und gccc / clang nicht identisch.

Wenn Sie beispielsweise ein 16-Bit-Feld ausfüllen müssen, müssen Sie einen Dummy-Maximalwert definieren, der diese Größe erfordert.

Die andere Möglichkeit besteht darin, reguläre int-Stile in den Strukturdefinitionen zu verwenden. Dann verzichtet man jedoch auf die Bequemlichkeit des Debuggers, den Wert anhand des Aufzählungsnamens anzuzeigen und stattdessen nur Ganzzahlen abzurufen.

Dann muss man wahrscheinlich angeben, dass die Struktur, die die Aufzählung enthält, gepackt und nicht aufgefüllt ist.

Antwort

Wenn kein Teil einer Variablen x ist const oder volatile und x ist nicht vom Array-Typ. dann macht die Anweisung…

x = x;

… so ziemlich nichts. Es ist gut geformt. Angenommen, x wurde zuvor initialisiert, ¹ ist es auch gut definiert. Die Zuweisung ist nicht Der Status des Programms kann mit einigen möglichen Ausnahmen nicht wirklich geändert werden (siehe unten).

Dies gilt auch dann, wenn x eine Typ.

struct foo {

char buf[42];

int x;

};

struct foo x = { "Hello World", 18 };

x = x; // no big deal.

Was ist also der „Fehler“? Es ist kein nützlicher Code, aber es gibt ziemlich viel Code, der zu dieser Beschreibung passt. Es ist nur ein Fehler , wenn Sie etwas anderes tun wollten und es verpasst haben.

[Nachtrag: Angesichts der Nutzlosigkeit dieser Aufgabe sind Compiler geneigt, davor zu warnen, da es ziemlich wahrscheinlich ist, dass Sie bedeutet etwas anderes.]

Warum das Bit über const und volatile? Die Einschränkung für const ist einfach: Es bedeutet „schreibgeschützt“, sodass Sie nicht darauf schreiben können. Zumindest nicht mit einfacher Zuordnung.

Die bezüglich volatile ist schwieriger. Dieses Schlüsselwort besagt, dass der von ihm qualifizierte Wert möglicherweise auf eine Weise geändert wird, die für die Implementierung nicht sichtbar ist, und dass das Schreiben darauf möglicherweise Nebenwirkungen hat. Ohne hier in ein Loch zu graben, sehen in der Praxis die einzigen einigermaßen genau definierten Operationen, die Sie an einem flüchtigen Objekt ausführen können, folgendermaßen aus:

volatile int v;

int i;

i = v; // reads from v once, places into i.

v = i; // writes to v once with the contents of i.

Mit volatile können Sie etwas mehr als das tun. aber nur geringfügig. Das ist ein Thema für einen anderen Tag. Es gibt einen Grund, warum C ++ 20 alle bis auf einige Verwendungen von volatile veraltet hat. Ihre Änderungen sehen ziemlich vernünftig aus.

Ich habe oben einige mögliche Ausnahmen erwähnt. Jonas Oberhauser erinnerte mich daran, dass jede Auffüllung in einem struct durch diese Zuweisung nicht unbedingt erhalten bleibt.

Außerdem ist es theoretisch möglich, dass sich die zugrunde liegende Darstellung für Objekte aufgrund der Zuweisung ändert , wenn derselbe Wert auf mehrere Arten dargestellt werden kann.

Hoffentlich ist Ihr Programm für beide Möglichkeiten unempfindlich. Wenn Sie sich jedoch jemals die zugrunde liegende -Darstellung des Objekts ansehen, können Sie Unterschiede feststellen. Funktionen wie memcmp können dies beispielsweise bemerken. Wenn Sie verwenden, geben Sie ebenfalls punning ein.

¹ Und wenn nicht, willkommen bei undefiniertes Verhalten, , da Sie wahrscheinlich gegen eine der folgenden Bedingungen verstoßen:

  • Der Wert eines Objekts mit automatischer Speicherdauer wird verwendet, solange es unbestimmt ist ( 6.2 .4 , 6.7.9 , 6.8 ).
  • Ein Wert, der ein Objekt mit automatischer Speicherdauer angibt, das mit der Registerspeicherklasse deklariert werden könnte, wird in einem Kontext verwendet, der Folgendes erfordert Wert des angegebenen Objekts, aber das Objekt ist nicht initialisiert. ( 6.3.2.1 ).

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.