2008-10-01 9 views
92

Sind C++ enums signiert oder unsigniert? Und durch Erweiterung ist es sicher, eine Eingabe zu validieren, indem Sie überprüfen, ob es < = Ihr maximaler Wert ist, und>> Ihren minimalen Wert weglassen (vorausgesetzt, Sie haben bei 0 angefangen und um 1 erhöht)?Sind C++ enums signiert oder unsigniert?

+0

Wenn wir einen Aufzählungstyp in einem Kontext verwenden, der das Zeichen der es erfordert, sind wir implizit eigentlich reden über die ENUM zu einem integralen Typ zu konvertieren. Der C++ 03-Standard besagt, dass dies durch Integral Promotion erfolgt, nichts, was mit dem zugrunde liegenden Typ der Enumeration zusammenhängt. Also, ich verstehe nicht, warum jede Antwort hier erwähnt, der zugrunde liegende Typ ist nicht durch den Standard definiert? Ich beschrieb das erwartete Verhalten hier: http://stackoverflow.com/questions/24802322/sign-of-c-enum-type-incorrect-after-converting-to-integral- Typ – JavaMan

Antwort

56

Sie sollten sich nicht auf eine bestimmte Darstellung verlassen. Lesen Sie die folgenden link. Außerdem gibt der Standard an, dass es implementation-defined ist, welcher Integraltyp als zugrunde liegender Typ für eine enum verwendet wird, außer dass er nicht größer als int sein soll, es sei denn, ein Wert kann nicht in int oder unsigned int passen.

Kurz gesagt: Sie können sich nicht darauf verlassen, dass eine Enum entweder signiert oder unsigniert ist.

+21

[Michael Burrs Antwort] (http://stackoverflow.com/a/159308/594137) (was den Standard zitiert), impliziert, dass Sie * sich darauf verlassen können, dass es signiert wird, wenn Sie einen Aufzählungswert als negativ definieren, da der Typ "alle angegebenen Aufzählungswerte darstellen kann in der Aufzählung ". –

4

Der Compiler kann entscheiden, ob enums signiert oder unsigniert sind.

Eine weitere Methode zur Validierung von Enums besteht darin, die Enumeration selbst als Variablentyp zu verwenden. Zum Beispiel:

enum Fruit 
{ 
    Apple = 0, 
    Banana, 
    Pineapple, 
    Orange, 
    Kumquat 
}; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana. 
19

Sie sollten nicht davon abhängen, dass sie signiert oder unsigniert sind. Wenn Sie sie explizit mit oder ohne Vorzeichen machen möchten, können Sie die folgenden Befehle verwenden:

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 
+10

Nur in Zukunft C++ 0x Standard. – dalle

+3

@dalle Microsoft Compilator ermöglicht auch getippte Enums http://msdn.microsoft.com/en-us/library/2dzy4k6e(v=vs.80).aspx – teodozjan

3

in Zukunft mit C++ 0x, strongly typed enumerations verfügbar sein wird, und mehrere Vorteile haben (wie zB Typsicherheit, explizite zugrundeliegende Typen oder explizites Scoping). Damit könnten Sie sich besser auf das Zeichen des Typs verlassen.

95

Gehen wir zur Quelle. Hier ist, was die C++ 03-Standard (ISO/IEC 14882: 2003) Dokument sagt in 7,2-5 (Enumeration Erklärungen):

Der zugrunde liegende Typ eines Aufzählungs ein integraler Typ ist, der alle darstellen können Aufzählungswerte definiert in die Aufzählung. Es ist Implementierung definiert, die integrale Typ wie der zugrunde liegende Typ verwendet wird für eine Aufzählung der Ausnahme, dass der zugrunde liegende Typ darf nicht größer seine als int, wenn der Wert eines enumerator nicht in einem int oder unsigned int passen.

Kurz gesagt, Ihr Compiler kann wählen (natürlich, wenn Sie negative Zahlen für einige Ihrer Werte haben, wird es signiert).

+0

Wie können wir vermeiden, Compiler-Vermutungen und sagen Sie ihm, ein zugrunde liegendes zu verwenden vorzeichenloser Typ, wenn alle Aufzählungswerte klein sind, positive ganze Zahlen? (Wir fangen einen UBsan-Befund ab, weil der Compiler einen Int auswählt und Int einen Überlauf erleidet. Der Wert ist vorzeichenlos und positiv, und unsere Verwendung hängt von einem unsignierten Wrap ab, um ein Dekrement oder einen "negativen Schritt" bereitzustellen). – jww

+0

@jww - das hängt davon ab, welchen Compiler Sie genau verwenden, denke ich. Da der Standard den zugrunde liegenden Typ nicht vorgibt und dies der Implementierung überlässt, müssen Sie in der Dokumentation Ihres Tools nachsehen, ob diese Option überhaupt möglich ist. Wenn Sie ein bestimmtes Verhalten in Ihrem Code garantieren möchten, warum sollte das Enum-Member, das Sie im Ausdruck verwenden, nicht umgewandelt werden? – ysap

12

Sie sollten sich nicht darauf verlassen, dass es entweder signiert oder nicht signiert ist. Gemäß dem Standard ist es implementierungsdefiniert, welcher Integraltyp als der zugrundeliegende Typ für eine Enumeration verwendet wird. In den meisten Implementierungen ist es jedoch eine Ganzzahl mit Vorzeichen.

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 

Schon jetzt aber einige einfache Validierung mithilfe der Enum erreicht werden kann als:

In C++ 0x strongly typed enumerations wird, die Sie den Typ eines ENUM wie angeben können hinzugefügt werden eine Variable oder Parametertyp wie folgt aus:

enum Fruit { Apple, Banana }; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit 
        // even though it has the same value as banana. 
+0

Ich denke, Ihr zweites Beispiel ist ein wenig verwirrt :) – Miral

3

Zusätzlich zu dem, was andere gesagt haben, bereits über/ohne Vorzeichen, hier ist, was der Standard sagt über die Reichweite eines Aufzählungstyp:

7.2 (6): "Für eine Aufzählung, bei der e (min) der kleinste Enumerator und e (max) der größte ist, sind die Werte der Aufzählung die Werte des zugrunde liegenden Typs im Bereich b (min) bis b (max), wobei b (min) und b (max) jeweils die kleinsten und größten Werte des kleinsten Bitfeldes sind, das e (min) und e (max) speichern kann. Es ist möglich, eine Aufzählung zu definieren, die Werte nicht definiert ist durch eines ihrer Enumeratoren hat „

So zum Beispiel:.

enum { A = 1, B = 4}; 

einen Aufzählungstyp definiert, wobei E (min) = 1 und E (max) ist 4. Ist der zugrunde liegende Typ int intendiert, dann hat das kleinste erforderliche Bitfeld 4 Bits, und wenn ints in Ihrer Implementierung Zweierkomplement sind, dann ist der gültige Bereich der Enumeration -8 bis 7. Wenn der zugrundeliegende Typ unsigniert ist, dann es hat 3 Bits und der Bereich ist 0 bis 7. Überprüfen Sie Ihre Compiler-Dokumentation, wenn Sie sich interessieren (wenn Sie beispielsweise ganzzahlige Werte außer Enumeratoren in den Aufzählungstyp einteilen möchten, müssen Sie wissen, ob der Wert im Bereich von die Aufzählung oder nicht - wenn nicht, ist der resultierende Enum-Wert nicht spezifiziert).

Ob diese Werte gültige Eingaben für Ihre Funktion sind, kann ein anderes Problem sein, als wenn sie gültige Werte des Aufzählungstyps sind. Ihr Prüfcode ist wahrscheinlich eher um den ersten als um den zweiten besorgt und sollte daher in diesem Beispiel mindestens> = A und < = B überprüfen.

4

Sogar einige alte Antworten haben 44 upvotes, ich neige dazu, mit ihnen allen zu widersprechen. Kurz gesagt, ich denke nicht, dass wir uns um die underlying type der enum kümmern sollten.

Zunächst einmal, C++ 03 Enum-Typ ist ein eigener eigener Typ ohne Vorzeichen. Da von C++ 03-Standard dcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types.... 

Wenn wir also über das Zeichen eines Aufzählungstyp sprechen, sagt beim Vergleich von 2 Enum Operanden mit dem < Operator, reden wir eigentlich über implizit den Aufzählungstyp Umwandeln etwas integraler Typ. Es ist das Zeichen dieses Integraltyps, der betrifft. Und wenn Enum zu integralem Typ Umwandlung, diese Aussage gilt:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5). 

und offenbar der zugrunde liegende Typ der Enumeration nichts mit der Integral Promotion zu tun bekommen. Da der Standard wie dieses Integral Promotion definiert:

4.5 Integral promotions conv.prom 
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration 
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long. 

Ganz gleich, ob ein Aufzählungstyp signed int oder unsigned int wird hängt davon ab, ob signed int alle Werte der definierten Aufzählungen enthalten, nicht den zugrunde liegenden Typ der Enumeration.

Meine weitere Frage Sign of C++ Enum Type Incorrect After Converting to Integral Type

+0

Es spielt eine Rolle, wenn Sie mit "-Wsign-Konvertierung" kompilieren. Wir verwenden es, um unbeabsichtigte Fehler in unserem Code zu erkennen. Aber *** + 1 ***, um den Standard zu zitieren und darauf hinzuweisen, dass ein enum keinen Typ ("signed" versus "unsigned") damit assoziiert hat. – jww