it-swarm.com.de

Festlegen der Größe des Aufzählungstyps in C

Lies bereits diese verwandte Frage , suchte aber etwas genaueres.

  • Gibt es eine Möglichkeit, Ihrem Compiler genau zu sagen, wie breit Ihre Enumeration sein soll?
  • Wenn ja, wie machst du das? Ich weiß, wie man es in C # angibt; wird es ähnlich in C gemacht?
  • Lohnt es sich überhaupt, es zu tun? Wenn der Aufzählungswert an eine Funktion übergeben wird, wird er trotzdem als int-Größe übergeben?
26
Will

Gibt es eine Möglichkeit, Ihren Compiler mitzuteilen speziell wie breit Sie wollen enum zu sein?

Im allgemeinen nicht. Nicht im Standard C.

Lohnt es sich überhaupt, es zu tun?

Das hängt vom Kontext ab. Wenn Sie davon sprechen, Parameter an Funktionen zu übergeben, dann lohnt es sich nicht (siehe unten). Wenn beim Erstellen von Aggregaten aus Aufzählungstypen Speicher eingespart werden soll, lohnt es sich möglicherweise, dies zu tun. In C können Sie jedoch einfach einen ganzzahligen Typ mit geeigneter Größe anstelle eines Aufzählungstyps in Aggregaten verwenden. In C (im Gegensatz zu C++) sind Enummentypen und Integer-Typen fast immer austauschbar.

Wird der Enumerationswert an eine Funktion übergeben, wird er trotzdem als int-Wert übergeben?

Viele (die meisten) Compiler übergeben heutzutage alle Parameter als Werte der natürlichen Word-Größe für die gegebene Hardwareplattform. Auf einer 64-Bit-Plattform werden beispielsweise viele Compiler unabhängig von ihrer tatsächlichen Größe alle Parameter als 64-Bit-Werte übergeben, selbst wenn der Typ int 32 Bit auf dieser Plattform enthält (daher wird er normalerweise nicht als "int" übergeben.) -sized "Wert auf einer solchen Plattform). Aus diesem Grund macht es keinen Sinn, die Aufzählungsgrößen für die Parameterübergabe zu optimieren.

17
AnT

Ich glaube, wenn Sie GCC verwenden, gibt es eine Flagge.

-fshort-enums

15
Nyx0uf

Sie können erzwingen, dass es mindestens eine bestimmte Größe hat, indem Sie einen geeigneten Wert definieren. Wenn Sie beispielsweise möchten, dass Ihr Enum mit der gleichen Größe wie eine int gespeichert wird, obwohl alle Werte in eine char passen, können Sie Folgendes tun:

typedef enum {
    firstValue = 1,
    secondValue = 2,

    Internal_ForceMyEnumIntSize = MAX_INT
} MyEnum;

Beachten Sie jedoch, dass das Verhalten von der Implementierung abhängig sein kann.

Wenn Sie einen solchen Wert an eine Funktion übergeben, wird er sowieso zu einem int erweitert. Wenn Sie jedoch Ihren Typ in einem Array oder einer Struktur verwenden, ist die Größe von Bedeutung. Wenn Sie sich wirklich für Elementgrößen interessieren, sollten Sie wirklich Typen wie int8_t, int32_t usw. verwenden.

8

Es gibt auch einen anderen Weg, wenn das Enum Teil einer Struktur ist:

struct something {
     :0;
   enum whatever field:CHAR_BIT;
     :0;
};

Die: 0; kann weggelassen werden, wenn das Aufzählungsfeld von normalen Feldern umgeben ist. Wenn zuvor ein anderes Bitfeld vorhanden ist, erzwingt die: 0 eine Byte-Ausrichtung zum nächsten Byte für das darauf folgende Feld.

7

In einigen Fällen kann dies hilfreich sein:

typedef uint8_t command_t;
enum command_enum
{
    CMD_IDENT                = 0x00,     //!< Identify command
    CMD_SCENE_0              = 0x10,     //!< Recall Scene 0 command
    CMD_SCENE_1              = 0x11,     //!< Recall Scene 1 command
    CMD_SCENE_2              = 0x12,     //!< Recall Scene 2 command
};

/* cmdVariable is of size 8 */
command_t cmdVariable = CMD_IDENT; 

Typ command_t hat einerseits die Größe 8 und kann für Variablen- und Funktionsparameter-Typ ..__ verwendet werden. Andererseits können Sie für die Zuweisung die Aufzählungswerte verwenden, die standardmäßig vom Typ int sind, der Compiler setzt sie jedoch bei der Zuweisung sofort um auf eine Variable vom Typ command_t.

Wenn Sie etwas Unsicheres tun, z. B. einen CMD_16bit = 0xFFFF, definieren und verwenden, werden Sie vom Compiler mit der folgenden Meldung gewarnt:

warnung: Große Ganzzahl implizit auf vorzeichenlosen Typ abgeschnitten [-Woverflow]

0
Julien

Dies hängt von den Werten ab, die für die Aufzählung zugewiesen wurden.

Bsp .: Wenn ein Wert größer als 2 ^ 32-1 gespeichert wird, ändert sich die für die gesamte Aufzählung zugewiesene Größe auf die nächste Größe.

Speichern Sie den Wert 0xFFFFFFFFFFFF in einer Enum-Variable. Wenn Sie versuchen, in einer 32-Bit-Umgebung zu kompilieren, wird eine Warnung ausgegeben.

0
user5057906

Auch wenn Sie strengen C Code schreiben, sind die Ergebnisse vom Compiler abhängig. Mit den Strategien aus diesem Thread habe ich einige interessante Ergebnisse erzielt ...

enum_size.c

#include <stdio.h>

enum __attribute__((__packed__)) PackedFlags {
    PACKED = 0b00000001,
};

enum UnpackedFlags {
    UNPACKED = 0b00000001,
};

int main (int argc, char * argv[]) {
  printf("packed:\t\t%lu\n", sizeof(PACKED));
  printf("unpacked:\t%lu\n", sizeof(UNPACKED));
  return 0;
}
$ gcc enum_size.c
$ ./a.out
packed:         4
unpacked:       4
$ gcc enum_size.c -fshort_enums
$ ./a.out
packed:         4
unpacked:       4
$ g++ enum_size.c
$ ./a.out
packed:         1
unpacked:       4
$ g++ enum_size.c -fshort_enums
$ ./a.out
packed:         1
unpacked:       1

In meinem obigen Beispiel habe ich den Modifikator __attribute__((__packed__)) erst verwendet, als ich mit der Verwendung des C++ - Compilers begonnen habe.

EDIT:

Der Verdacht von @ technosaurus war richtig.

Indem ich die Größe von sizeof(enum PackedFlags) anstelle von sizeof(PACKED) überprüfe, sehe ich die Ergebnisse, die ich erwartet hatte ...

  printf("packed:\t\t%lu\n", sizeof(enum PackedFlags));
  printf("unpacked:\t%lu\n", sizeof(enum UnpackedFlags));

Ich sehe jetzt die erwarteten Ergebnisse von gcc:

$ gcc enum_size.c
$ ./a.out
packed:         1
unpacked:       4
$ gcc enum_size.c -fshort_enums
$ ./a.out
packed:         1
unpacked:       1
0
Zak

Wie @ Nyx0uf sagt , hat GCC ein Flag, das Sie setzen können:

-fshort-enums 

Weisen Sie einem Aufzählungstyp nur so viele Bytes zu, wie für den deklarierten Bereich möglicher Werte erforderlich sind. Insbesondere entspricht der Aufzählungstyp dem kleinsten ganzzahligen Typ, der über ausreichend Platz verfügt. 

Warnung: Die Option -fshort-enums bewirkt, dass GCC Code generiert, der nicht binär mit Code kompatibel ist, der ohne diese Option generiert wurde. Verwenden Sie diese Option, um eine nicht standardmäßige binäre Anwendungsschnittstelle zu verwenden. 

Quelle: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

Zusätzliche großartige Lektüre für allgemeine Einblicke:https://www.embedded.fm/blog/2016/6/28/how-big-is-an-enum .
Interessant ... Beachten Sie die Zeile, die ich unten gelb hervorgehoben habe!

 enter image description here

0
Gabriel Staples