2013-02-11 5 views
3

Je sais que les types de données plus faibles sont jetés dans les types de données plus élevées (par exemple int -> unsigned int -> float -> etc.) mais je ne suis pas sûr de ce qui suit:C++ conversion du type implicite de non signé signé

int var = 5u - 10; // var = -5 
auto var = 5u - 10; // var = 4294967291 

5u est non signé mais dans le premier cas, pourquoi -10 (nombre entier signé) n'est pas converti en valeur non signée alors que dans le second cas il le fait? Dans le premier cas, la valeur signée n'est pas convertie en une valeur non signée et elle est pour moi

+3

'5u - 10' évalue à un' non signé 'selon C Standard. – sgarizvi

+3

C ou C++? Choisissez-en un. –

+7

Le résultat de la soustraction est 'unsigned' dans les deux cas, mais dans le premier cas, le résultat est converti en type de destination. Par conséquent '4294967291' est converti en' -5' – Praetorian

Répondre

3

Il n'y a pas de "littéral entier signé": 5u - 10 est en fait la soustraction de 10 à partir de 5u.

Le résultat (de la soustraction) est non signé, et va déborder, ce qui donne comme résultat un « 5 nombres inférieurs à la survolée 0 » (= 4294967291 2 -5)

La déclaration d'abord initialiser int, d'où la constante de temps de compilation non signée est réinterprétée comme int. Le résultat est correct (-5) car votre matériel utilise l'arithmétique 2s-complément. (-5 et 4294967291 sont le même modèle 32 bits)

La deuxième instruction initialise une variable dont le type est déduit par le littéral. Et c'est unsigned.

2

Tout d'abord, parce que vous utilisez auto, le compilateur choisira unsigned dans votre deuxième exemple.

Les numéros signés et non signés sont stockés de la même manière en interne. C'est juste la façon dont le nombre est interprété quand il est imprimé qui fait la différence [et dans les comparaisons, comme les nombres 'négatifs' signés sont inférieurs à 0, où les nombres non signés ne peuvent être inférieurs à zéro] - les nombres signés sont vérifiés si elles sont 'négatives', et imprimées comme un signe moins et le nombre original nié. Les nombres non signés sont juste traités comme ce que la représentation interne devient lorsqu'elle est imprimée. Donc, les valeurs que vous voyez sont juste les deux représentations différentes du même nombre - signées et non signées respectivement.

2

Les côtés droits de les deux de vos exemples fonctionnent entièrement dans le domaine de type non signé. C'est à dire. vos deux expressions 5u - 10 se comportent de manière identique, ce qui n'est pas surprenant, car ils sont identiques. Il n'y a aucune conversion à int (comme vous semblez le supposer à tort) dans l'expression 5u - 10 dans les deux cas. L'expression 5u - 10 est toujours évaluée dans le domaine de type non signé et produit un résultat non signé égal à UINT_MAX + 1 - 5. Dans la première initialisation, vous essayez de forcer cette valeur dans une variable de type int, ce qui entraîne un débordement avec le comportement défini par l'implémentation. Dans votre cas, votre implémentation s'est comportée de sorte que var a acquis la valeur -5. En d'autres termes, le fait que vous vous retrouviez avec -5 en var n'a pas d'explication définitive dans le domaine de abstrait langage C++. Le résultat que vous observez est juste une bizarrerie de votre compilateur. Dans un autre compilateur, la première initialisation peut produire une valeur différente dans var.

Dans le second cas, le type de l'expression (qui est à nouveau unsigned) devient le type de la variable, qui est initialisée avec la valeur non signée sans débordements.

1

En C et C++, dans la grande majorité des cas, le type d'une expression est déterminé à partir de l'expression elle-même, sans tenir compte du contexte dans lequel elle apparaît.

int var = 5u - 10; 

5u est de type unsigned int; 10 est de type int. Les règles de l'opérateur - provoquent la conversion de l'argument int en unsigned int, ce qui rend l'expression équivalente à 5u - 10u. Le résultat est UINT_MAX + 1 - 10, un très grand nombre. L'initialisation convertit implicitement cela de unsigned int à signed int. Puisque cette valeur (presque certainement) n'est pas représentable comme int, le résultat de la conversion est défini par l'implémentation. Dans presque toutes les implémentations existantes, la conversion réinterprète simplement la représentation non signée comme s'il s'agissait d'une valeur signée, aboutissant à -5. (Ceci s'applique aux systèmes qui utilisent une représentation en complément à deux pour les valeurs négatives, la simplicité résultante des conversions signées/non signées est l'une des raisons pour lesquelles le complément à deux est si largement utilisé.)

Notez qu'il ne serait pas possible de var pour avoir la valeur 4294967291; la plus grande valeur qu'un int peut contenir sur votre système est (probablement) 2147483647.

auto var = 5u - 10; 

5u - 10 est évalué de la même manière que précédemment, ce qui un résultat unsigned int de UINT_MAX + 1 - 5 ou 4294967291 sur votre système. Le auto signifie que var prend le type de l'expression, unsigned int, donc aucune conversion n'est effectuée. (Sur un système 16 bits int, le résultat serait 65531.)

En réponse à votre question, la 10 constante est converti de int à unsigned int dans les deux cas.

Questions connexes