Les énumérations C ++ sont-elles signées ou non signées? Et par extension, est-il sûr de valider une entrée en vérifiant qu'elle est <= votre valeur max, et en omettant> = votre valeur min (en supposant que vous avez commencé à 0 et incrémenté de 1)?
107
Réponses:
Vous ne devriez pas vous fier à une représentation spécifique. Lisez le lien suivant . De plus, la norme dit que le type intégral utilisé comme type sous-jacent pour une énumération est défini par l'implémentation, sauf qu'il ne doit pas être plus grand que int, sauf si une valeur ne peut pas entrer dans int ou un int unsigned.
En bref: vous ne pouvez pas compter sur une énumération signée ou non signée.
la source
Allons à la source. Voici ce que dit le document de la norme C ++ 03 (ISO / IEC 14882: 2003) dans 7.2-5 (Déclarations d'énumération):
En bref, votre compilateur peut choisir (évidemment, si vous avez des nombres négatifs pour certaines de vos valeurs d'ennumération, il sera signé).
la source
Vous ne devriez pas dépendre de leur signature ou non. Si vous souhaitez les rendre explicitement signés ou non signés, vous pouvez utiliser ce qui suit:
la source
Vous ne devriez pas vous fier à ce qu'il soit signé ou non signé. Selon la norme, l'implémentation définit le type intégral utilisé comme type sous-jacent pour une énumération. Dans la plupart des implémentations, cependant, il s'agit d'un entier signé.
En C ++ 0x, des énumérations fortement typées seront ajoutées, ce qui vous permettra de spécifier le type d'une énumération telle que:
Même maintenant, cependant, une validation simple peut être obtenue en utilisant l'énumération comme variable ou type de paramètre comme ceci:
la source
Le compilateur peut décider si les énumérations sont signées ou non.
Une autre méthode de validation des énumérations consiste à utiliser l'énumération elle-même comme type de variable. Par exemple:
la source
Même certaines vieilles réponses ont obtenu 44 votes positifs, j'ai tendance à ne pas être d'accord avec toutes. En bref, je ne pense pas que nous devrions nous soucier
underlying type
de l'énumération.Tout d'abord, le type Enum C ++ 03 est un type distinct qui n'a pas de concept de signe. Depuis la norme C ++ 03
dcl.enum
Ainsi, lorsque nous parlons du signe d'un type enum, par exemple lorsque nous comparons 2 opérandes enum à l'aide de l'
<
opérateur, nous parlons en fait de convertir implicitement le type enum en un type intégral. C'est le signe de ce type intégral qui compte . Et lors de la conversion d'énumération en type intégral, cette instruction s'applique:Et, apparemment, le type sous-jacent de l'énumération n'a rien à voir avec la promotion intégrale. Puisque la norme définit la promotion intégrale comme ceci:
Ainsi, si un type enum devient
signed int
ouunsigned int
dépend de sisigned int
peut contenir toutes les valeurs des énumérateurs définis, pas le type sous-jacent de l'énumération.Voir ma question connexe Signe du type d'énumération C ++ incorrect après la conversion en type intégral
la source
-Wsign-conversion
. Nous l'utilisons pour aider à détecter les erreurs involontaires dans notre code. Mais +1 pour avoir cité la norme, et souligné qu'une énumération n'a aucun type (signed
versusunsigned
) qui lui est associé.À l'avenir, avec C ++ 0x, des énumérations fortement typées seront disponibles et présenteront plusieurs avantages (tels que la sécurité de type, les types sous-jacents explicites ou la portée explicite). Avec cela, vous pourriez être mieux assuré du signe du type.
la source
En plus de ce que d'autres ont déjà dit à propos des signés / non signés, voici ce que dit la norme sur la plage d'un type énuméré:
7.2 (6): "Pour une énumération où e (min) est le plus petit énumérateur et e (max) est le plus grand, les valeurs de l'énumération sont les valeurs du type sous-jacent dans l'intervalle b (min) à b (max ), où b (min) et b (max) sont respectivement les valeurs les plus petites et les plus grandes du plus petit champ de bits pouvant stocker e (min) et e (max). Il est possible de définir une énumération dont les valeurs ne sont pas définies par l'un de ses agents recenseurs. "
Donc par exemple:
définit un type énuméré où e (min) est 1 et e (max) est 4. Si le type sous-jacent est signé int, alors le plus petit champ de bits requis a 4 bits, et si ints dans votre implémentation est un complément à deux, alors la plage valide de l'énumération est de -8 à 7. Si le type sous-jacent n'est pas signé, il a 3 bits et la plage est comprise entre 0 et 7. Vérifiez la documentation de votre compilateur si cela vous intéresse (par exemple, si vous souhaitez convertir des valeurs intégrales autres que les énumérateurs en type énuméré, vous devez savoir si la valeur est dans la plage de l'énumération ou non - sinon la valeur d'énumération résultante n'est pas spécifiée).
Le fait que ces valeurs soient des entrées valides pour votre fonction peut être un problème différent de savoir si ce sont des valeurs valides du type énuméré. Votre code de vérification est probablement préoccupé par le premier plutôt que par le second, et donc dans cet exemple devrait au moins vérifier> = A et <= B.
la source
Vérifiez-le avec
std::is_signed<std::underlying_type
+ les énumérations étendues par défaut àint
https://en.cppreference.com/w/cpp/language/enum implique:
main.cpp
GitHub en amont .
Compilez et exécutez:
Production:
Testé sur Ubuntu 16.04, GCC 6.4.0.
la source