Ist es sicher, eine Aufzählung in einem Bitfeld zu verwenden?
Lesezeit: 5 Minuten
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
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
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.
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).
13799600cookie-checkIst es sicher, eine Aufzählung in einem Bitfeld zu verwenden?yes
Mit wie vielen Compilern hast du das schon probiert?
– Honky-Tonk
16. August 2012 um 8:26 Uhr