Ist es sicher, eine Aufzählung in einem Bitfeld zu verwenden?

Lesezeit: 5 Minuten

Benutzer-Avatar
Ecken

Sprich, ich habe die folgende Struktur:

typedef struct my_struct{
    unsigned long       a;
    unsigned long       b;
    char*               c;
    unsigned int        d1  :1;
    unsigned int        d2  :4;
    unsigned int        d3  :4;
    unsigned int        d4  :23;
} my_type, *p_type;

Das Feld d3 ist derzeit definiert durch #defines, die von reichen 0x00 bis um 0x0D.

Eigentlich, d3 ist eine Aufzählung. Es ist also verlockend, weiterzumachen und zu ersetzen

    unsigned int        d3  :4;

durch

    my_enum             d3  :4;

Ist das sicher/erlaubt?

Der Code muss mit verschiedenen kompiliert werden

  • Compiler (GCC, Visual Studio, eingebettetes Zeug)
  • Plattformen (Win32, Linux, Embedded Stuff)
  • Konfigurationen (kompilieren als C, kompilieren als C++)

Offensichtlich könnte ich die Definition von verlassen d3 so wie es ist und nutze die Enum in meinem Code, weise es zu d3 und so weiter, aber das wird nicht mit C++ funktionieren.

  • Mit wie vielen Compilern hast du das schon probiert?

    – Honky-Tonk

    16. August 2012 um 8:26 Uhr

Benutzer-Avatar
Bis in alle Ewigkeit

Es ist in allen C++-Compilern erlaubt, die Standard unterstützen.

C++03-Standard 9.6/3

Ein Bitfeld muss vom Typ Ganzzahl oder Aufzählung sein (3.9.1). Es ist implementierungsabhängig, ob ein einfaches (weder explizit signiertes noch unsigned) char-, short-, int- oder long-Bitfeld signiert oder unsigniert ist.

C++03-Standard 9.6/4

Wenn der Wert eines Enumerators in einem Bitfeld des gleichen Enumerationstyps gespeichert wird und die Anzahl der Bits im Bitfeld groß genug ist, um alle Werte dieses Enumerationstyps aufzunehmen, den ursprünglichen Enumeratorwert und den Wert des Bitfeldes sollen gleich sein.

Beispiel

enum BOOL { f=0, t=1 };

struct A {
    BOOL b:1;
};

void f() {
    A a;
    a.b = t;
    a.b == t // shall yield true
}

Sie können jedoch nicht davon ausgehen, dass enum einen unsignierten zugrunde liegenden Typ hat.

C++03-Standard 7.2/5

Der zugrunde liegende Typ einer Enumeration ist ein ganzzahliger Typ, der alle in der Enumeration definierten Enumeratorwerte darstellen kann. Es ist implementierungsdefiniert, welcher ganzzahlige Typ als zugrunde liegender Typ für eine Aufzählung verwendet wird, außer dass der zugrunde liegende Typ nicht größer als int sein darf, es sei denn, der Wert eines Enumerators passt nicht in ein int oder unsigned int

  • Dies ist eine alte Antwort, daher möchte ich nur darauf hinweisen, dass Sie seit C ++ 11 einen (ganzzahligen) Basistyp für Ihre Aufzählungen scannen.

    – Spencer

    21. März um 12:38 Uhr

Benutzer-Avatar
Jens Gustedt

Die Antwort wird für C und C++ unterschiedlich sein, dies ist eine für C.

In C sind Bitfelder beschränkt auf signed int, unsigned int, _Bool und int was in diesem Zusammenhang eine der ersten beiden sein kann. Compiler-Implementierer können diese Liste nach Belieben ergänzen, müssen jedoch die Typen dokumentieren, die sie unterstützen.

Um Ihre Frage zu beantworten: Wenn Sie absolut sicher sein wollen, dass Ihr Code auf alle C-Compiler portierbar ist, nein, verwenden Sie eine enum Typ ist keine Option.

Der entsprechende Absatz aus der aktuellen Norm lautet:

Ein Bitfeld muss einen Typ haben, der eine qualifizierte oder nicht qualifizierte Version von _Bool, signed int, unsigned int oder einem anderen implementierungsdefinierten Typ ist. Es ist implementierungsabhängig, ob atomare Typen zulässig sind.

  • Ich gehe meistens mit #ifdef __GNUC__ #define ENUMBF(type) __extension__ type #else #define ENUMBF(type) unsigned #endif. Und später setzen ENUMBF(myenum) field:x; in meine Strukturen. Der Code ist weniger schön, aber Sie verpassen keine wichtigen gcc-Warnungen, z. B. wenn Ihr Bitfeld zu klein ist, weil ein Kollege mehr Fälle zur Aufzählung hinzugefügt hat …

    – MatzeBraun

    25. November 2014 um 7:58 Uhr


Nein.

Bitfelder werden zwischen Compilern deutlich unterschiedlich implementiert. Wenn Sie ein Bitfeld mit zwei Werten, null und eins, definieren und versuchen, ein enum-typisiertes Bitfeld zu haben, können Sie auf folgende Probleme stoßen:

Das Bitfeld wird mit gcc und clang unsigniert, aber mit VC++ signiert. Das bedeutet, dass Sie zum Speichern von Null und Eins ein Zwei-Bit-Bitfeld benötigen (ein Ein-Bit-Bitfeld mit Vorzeichen kann nur Null und negative Eins speichern).

Dann müssen Sie sich um das Packen kümmern. VC++ packt benachbarte Bitfelder nur dann in denselben Sicherungsspeicher, wenn ihre Größen übereinstimmen. Ich bin mir nicht sicher, wie die Regeln für gcc und clang lauten, aber für VC++ ist der Standard-Sicherungsspeicher für ein Bitfeld ein int. Eine Reihe von Bitfeldern, die beispielsweise eine Mischung aus bool und enum sind, werden mit VC++ äußerst schlecht gepackt.

Sie könnten versuchen, dies mit C++ 11-typisierten Aufzählungen zu lösen:

enum Foo : unsigned char { eins, zwei };

aber dann beschwert sich gcc, wenn Sie dies in einem Ein-Bit-Bit-Feld verwenden:

Warnung: „bitfieldTest::g“ ist zu klein, um alle Werte von „enum Foo“ aufzunehmen [enabled by default]

Es scheint, als gäbe es kein Gewinnen.

  • Es ist interessant, dass für enum class Aus irgendeinem Grund ist es viel besser: Alle Compiler verwenden standardmäßig int, der zugrunde liegende Typ kann ohne Warnung in gcc geändert werden. Das einzige Problem ist, dass gcc einen Fehler hatte, bei dem es in allen Fällen für dieselben fehlerhaften Warnungen gab enum class für eine ganze Weile.

    – Predelnik

    24. September 2020 um 14:56 Uhr

  • Dies ist jetzt veraltet; gcc hat den Fehler behoben, der dies bewirkt. Sie können jetzt eine zweiwertige Aufzählung in ein Ein-Bit-Bitfeld einfügen.

    – Spencer

    21. März um 12:51 Uhr

Benutzer-Avatar
md5

In C ist es ein undefiniertes Verhalten, weil ein Bit-Feld nur haben kann signed int, int oder unsigned int Typen (bzw _Bool mit C99).

6.5.2.1 :

Ein Bitfeld muss einen Typ haben, der eine qualifizierte oder nicht qualifizierte Version von int, unsigned int oder signed int ist. Ob die höherwertige Bitposition eines (möglicherweise qualifizierten) „einfachen“ Int-Bitfelds als Vorzeichenbit behandelt wird, ist implementierungsdefiniert. Ein Bitfeld wird als ganzzahliger Typ interpretiert, der aus der angegebenen Anzahl von Bits besteht.

Ansonsten wird es heute von einigen Compilern als Erweiterung akzeptiert (vgl. implementierungsdefiniertes Verhalten der Erweiterungen im Standard).

1379960cookie-checkIst es sicher, eine Aufzählung in einem Bitfeld zu verwenden?

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

Privacy policy