Sind C ++ - Aufzählungen signiert oder nicht signiert? Und ist es sicher, eine Eingabe zu validieren, indem Sie überprüfen, ob sie <= Ihr Maximalwert ist, und> = Ihren Minimalwert weglassen (vorausgesetzt, Sie haben bei 0 begonnen und um 1 erhöht)?
107
Antworten:
Sie sollten sich nicht auf eine bestimmte Darstellung verlassen. Lesen Sie den folgenden Link . Außerdem besagt der Standard, dass implementierungsdefiniert ist, welcher Integraltyp als zugrunde liegender Typ für eine Aufzählung verwendet wird, mit der Ausnahme, dass er nicht größer als int sein darf, es sei denn, ein Wert kann nicht in int oder ein vorzeichenloses int passen.
Kurz gesagt: Sie können sich nicht darauf verlassen, dass eine Aufzählung signiert oder nicht signiert ist.
quelle
Gehen wir zur Quelle. Im Dokument zum C ++ 03-Standard (ISO / IEC 14882: 2003) heißt es in 7.2-5 (Aufzählungserklärungen):
Kurz gesagt, Ihr Compiler kann wählen (wenn Sie für einige Ihrer Aufzählungswerte negative Zahlen haben, wird diese natürlich signiert).
quelle
Sie sollten sich nicht darauf verlassen, dass sie signiert oder nicht signiert sind. Wenn Sie sie explizit signiert oder nicht signiert machen möchten, können Sie Folgendes verwenden:
quelle
Sie sollten sich nicht darauf verlassen, dass es signiert oder nicht signiert ist. Gemäß dem Standard ist implementierungsdefiniert, welcher Integraltyp als zugrunde liegender Typ für eine Aufzählung verwendet wird. In den meisten Implementierungen handelt es sich jedoch um eine vorzeichenbehaftete Ganzzahl.
In C ++ 0x werden stark typisierte Aufzählungen hinzugefügt, mit denen Sie den Typ einer Aufzählung angeben können, z.
Selbst jetzt kann eine einfache Validierung erreicht werden, indem die Aufzählung als Variablen- oder Parametertyp wie folgt verwendet wird:
quelle
Der Compiler kann entscheiden, ob Aufzählungen signiert oder nicht signiert sind.
Eine andere Methode zum Überprüfen von Aufzählungen besteht darin, die Aufzählung selbst als Variablentyp zu verwenden. Beispielsweise:
quelle
Sogar einige alte Antworten haben 44 positive Stimmen erhalten, ich stimme allen nicht zu. Kurz gesagt, ich denke nicht, dass wir uns um das kümmern sollten
underlying type
die Aufzählung .Zunächst einmal ist der C ++ 03-Aufzählungstyp ein eigenständiger Typ ohne Vorzeichenkonzept. Seit ab C ++ 03 Standard
dcl.enum
Wenn wir also über das Vorzeichen eines Aufzählungstyps sprechen, beispielsweise wenn wir zwei Aufzählungsoperanden mit dem
<
Operator vergleichen, sprechen wir tatsächlich über die implizite Konvertierung des Aufzählungstyps in einen ganzzahligen Typ. Es ist das Zeichen dieses integralen Typs, das zählt . Und wenn Sie enum in einen integralen Typ konvertieren, gilt diese Aussage:Und anscheinend hat der zugrunde liegende Typ der Aufzählung nichts mit der integralen Förderung zu tun. Da der Standard Integral Promotion wie folgt definiert:
Ob ein Aufzählungstyp wird
signed int
oderunsigned int
davon abhängt, ob ersigned int
alle Werte der definierten Enumeratoren enthalten kann, nicht den zugrunde liegenden Typ der Aufzählung.Siehe meine verwandte Frage Zeichen des C ++ - Aufzählungstyps nach Konvertierung in einen integralen Typ falsch
quelle
-Wsign-conversion
. Wir verwenden es, um unbeabsichtigte Fehler in unserem Code zu erkennen. Aber +1, um den Standard zu zitieren und darauf hinzuweisen, dass einer Aufzählung kein Typ (signed
versusunsigned
) zugeordnet ist.In Zukunft werden mit C ++ 0x stark typisierte Aufzählungen verfügbar sein und mehrere Vorteile haben (z. B. Typensicherheit, explizite zugrunde liegende Typen oder explizites Scoping). Damit können Sie sich des Zeichens des Typs besser sicher sein.
quelle
Zusätzlich zu dem, was andere bereits über signiert / nicht signiert gesagt haben, sagt der Standard Folgendes über den Bereich eines aufgezählten Typs:
7.2 (6): "Bei einer Aufzählung, bei der e (min) der kleinste Aufzähler 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 Bitfelds sind, in dem e (min) und e (max) gespeichert werden können. Es ist möglich, eine Aufzählung zu definieren, deren Werte nicht definiert sind von einem seiner Aufzähler. "
Also zum Beispiel:
definiert einen Aufzählungstyp, wobei e (min) 1 und e (max) 4 ist. Wenn der zugrunde liegende Typ int signiert ist, hat das kleinste erforderliche Bitfeld 4 Bits, und wenn Ints in Ihrer Implementierung Zweierkomplement sind, ist der gültige Bereich von Die Aufzählung ist -8 bis 7. Wenn der zugrunde liegende Typ ohne Vorzeichen ist, hat er 3 Bits und der Bereich liegt zwischen 0 und 7. Überprüfen Sie Ihre Compiler-Dokumentation, wenn Sie sich interessieren (zum Beispiel, wenn Sie andere Integralwerte als Enumeratoren in die umwandeln möchten Aufzählungstyp, dann müssen Sie wissen, ob der Wert im Bereich der Aufzählung liegt oder nicht - wenn nicht, ist der resultierende Aufzählungswert nicht angegeben).
Ob diese Werte eine gültige Eingabe für Ihre Funktion sind, hängt möglicherweise davon ab, ob es sich um gültige Werte vom Aufzählungstyp handelt. Ihr Prüfcode ist wahrscheinlich eher um den ersteren als um den letzteren besorgt und sollte daher in diesem Beispiel zumindest> = A und <= B prüfen.
quelle
Überprüfen Sie dies mit den
std::is_signed<std::underlying_type
Aufzählungen mit + Gültigkeitsbereichint
https://en.cppreference.com/w/cpp/language/enum impliziert:
main.cpp
GitHub stromaufwärts .
Kompilieren und ausführen:
Ausgabe:
Getestet unter Ubuntu 16.04, GCC 6.4.0.
quelle