182 votes

Que se passe-t-il si vous statique_cast valeur invalide à enum classe?

Considérez ce code C ++11:

 enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);
 

Supposons que data [0] soit en réalité 100. À quoi correspond la couleur définie selon la norme? En particulier, si je fais plus tard

 switch (color) {
    // ... red and yellow cases omitted
    default:
        // handle error
        break;
}
 

la norme garantit-elle que le défaut sera atteint? Sinon, quel est le moyen le plus approprié, le plus efficace et le plus élégant de rechercher une erreur ici?

MODIFIER:

En prime, la norme donne-t-elle des garanties à ce sujet, mais en termes simples?

159voto

dyp Points 19641

Qu'est-ce que le jeu de couleurs selon la norme?

Répondre par une citation de la Norme:

[expr.statique.distribution]/10

Une valeur de l'intégrale ou type d'énumération peut être converties explicitement à un type d'énumération. La valeur est inchangée si la valeur d'origine est à l'intérieur de la gamme des valeurs d'énumération (7.2). Sinon, la valeur est indéterminée (et peut-être pas dans cette gamme).

Voyons la gamme des valeurs d'énumération: [dcl.enum]/7

Pour une énumération dont le sous-jacent est de type fixe, les valeurs de l'énumération sont les valeurs du type sous-jacent.

Par conséquent, pour data[0] == 100, la valeur est spécifiée(*), et non à un Comportement indéterminé (UB) est impliqué. Plus généralement, comme vous le lancez à partir du type sous-jacent pour le type d'énumération, sans aucune valeur en data[0] peut conduire à l'AC pour l' static_cast.

(*) char est nécessaire d'être au moins 8 bits de large, mais n'est pas obligatoire pour être unsigned. La valeur maximale stockable est nécessaire d'être au moins 127 conformément à l'Annexe E de la Norme C99.


Comparer à [expr]/4

Si, lors de l'évaluation d'une expression, le résultat n'est pas définie mathématiquement ou pas dans la gamme des représentable valeurs pour son type, le comportement est indéfini.

Donc, ce pourrait facilement conduire à l'UB si la valeur était assez grand, par exemple, static_cast<Color>(10000);.


Maintenant, l' switch déclaration:

[stmt.commutateur]/2

La condition doit être de type intégral, type d'énumération, de classe ou de type. [...] Intégrale les promotions sont effectuées.

[conv.bal]/4

Un prvalue d'un non délimité type d'énumération dont le sous-jacent est de type fixe (7.2) peut être converti en un prvalue de son type sous-jacent. En outre, si la promotion intégrale peut être appliqué à son type sous-jacent, un prvalue d'un non délimité type d'énumération dont le sous-jacent est de type fixe peut également être converti en un prvalue de l'promu type sous-jacent.

Remarque: Le type sous-jacent d'une étendue enum w/o enum-de base est de int, pour les non délimité enums le type sous-jacent est de la mise en œuvre définies, mais qui est nécessaire pour être plus petit que int si int peut contenir les valeurs de tous les agents recenseurs

Pour une énumération non délimité, ce qui nous amène à /1

Un prvalue d'un entier de type autre que bool, char16_t, char32_tou wchar_t dont la conversion d'entier rang (4.13) est inférieur au rang d' int peut être converti en prvalue de type int si int peut représenter toutes les valeurs du type de source; sinon, la source prvalue peut être converti en prvalue de type unsigned int.

Dans le cas d'une non délimité énumération, nous traiterait ints ici. Pour l'étendue des énumérations (enum class et enum struct), aucune partie intégrante de la promotion s'applique. En quelque sorte, la promotion intégrale ne conduit pas à UB, soit, comme la valeur stockée dans la gamme du type sous-jacent et dans la gamme de int.

[stmt.commutateur]/5

Lorsque l' switch instruction est exécutée, sa condition est évaluée et comparée avec chaque cas constant. Si l'une de ces constantes est égale à la valeur de l'état, le contrôle est passé à l'instruction suivant la correspondance case label. Si aucun case constante correspond à la condition, et si il y a un default label, le contrôle passe à l'état marqué par l' default label.

L' default de l'étiquette doit être frappé.

Remarque: On pourrait prendre un autre regard sur l'opérateur de comparaison, mais il n'est pas utilisé explicitement dans la "comparaison". En fait, il n'y a aucun indice qu'elle introduirait UB pour l'étendue ou non délimité les énumérations dans notre cas.


En bonus, la norme apporter aucune garantie quant à ce sujet, mais avec la plaine enum?

Si oui ou non l' enum l'étendue de ne pas faire de différence. Cependant, il y a une différence si oui ou non le type sous-jacent est fixe. Le complet [decl.enum]/7 est:

Pour une énumération dont le sous-jacent est de type fixe, les valeurs de l'énumération sont les valeurs du type sous-jacent. Sinon, pour une énumération où emin est le plus petit agent recenseur et emax est le plus grand, les valeurs de l'énumération sont les valeurs dans la plage bmin à bmax, définis comme suit: Laissez - K être 1 pour un complément à deux de la représentation et de l' 0 pour un complément ou un signe-amplitude de la représentation. bmax est la plus petite valeur supérieure ou égale à max(|emin| − K, |emax|) et égale à 2M − 1, où M est un entier non négatif. bmin est égale à zéro si emin est non-négative et (bmax + K) autrement.

Heureusement, votre enum la plus petite de l'agent recenseur est - red = 0x1, alors max(|emin| − K, |emax|) est égal à |emax| en tout cas, qui est - yellow = 0x2. La plus petite valeur supérieure ou égale à 2, ce qui est égal à 2M - 1 pour un entier positif M est 3 (22 - 1). (Je pense que l'intention est de permettre la plage de mesure de 1-bit-étapes). Il s'ensuit que bmax est - 3 et bmin est - 0.

Par conséquent, 100 serait en dehors de la plage de l'enum, et l' static_cast serait de produire une valeur quelconque, ce qui pourrait conduire à l'AC par [expr]/4.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X