2012-06-04 5 views
7

Le langage que j'utilise est C. Le type de x et n est int.La différence entre ~ (x-1) et ~ x + 1 lorsque x = 0x80000000

I ont un code de ligne comme suit

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

Elle montre la valeur de x, n et deux méthodes de décalage de n bits du nombre de complément de x. Lorsque x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000, mais lorsque vous changez ces deux bits de n bits, les résultats sont différents.

BTW, si je changeais 0xffffffff à ~ 1 + 1 (cela signifie que ~ (x + (~ 1 + 1)), le résultat est le même que ~ x + 1

Je me demande pourquoi cela est arrivé. Merci .

+0

[Est-ce que "(uint16_t) -1" Code C Portable?] (Http://embeddedgurus.com/barr-code/2011/06/is-uint16_t-1-portable-c-code/) – Lundin

+0

@Lundin Cet article est faux. '(uint16_t) -1' ** est ** garanti par le standard pour produire' 0xFFFF' si l'implémentation fournit ce type dans 'stdint.h'. (Bien sûr, rien n'est garanti si c'est votre propre typedef.) Il n'y a pas d'ambiguïté, les types à largeur fixe ne doivent pas contenir de bits de remplissage, donc ils ne sont même pas limités aux bits de valeur (eh bien, sont seulement des bits de valeur dans 'uintN_t'). –

Répondre

4

La réponse maintenant supprimée par Pavan Manjunath avait la bonne réponse pour un cas, en supposant que int est comme d'habitude un type de 32 bits. Le nombre entier constant

0xffffffff 

a la valeur 2^32 - 1 et qui ne soit pas représentable par un int, mais il est représentable comme un unsigned int. Donc, son type est unsigned int (6.4.4.1). Par conséquent x est converti en unsigned int pour l'addition, et

((~(x+0xffffffff))>>n) 

évalue comme

((~(0x80000000u + 0xffffffffu)) >> n) 
((~0x7fffffffu) >> n) 
(0x80000000u >> n) 

avec la valeur 2^(31-n) si 0 <= n < 32 (son comportement indéfini si n est en dehors de cette plage).

Pour l'autre cas, la réponse est correcte ouah, quand x = 0x80000000 est un int, ~0x8000000 = 0x7fffffff = INT_MAX et INT_MAX + 1 est un comportement non défini comme dépassement d'entier signé.

Néanmoins, un comportement commun est en boucle, puis le résultat de l'addition est l'entier signé 0x80000000 et le déplacement à droite des entiers négatifs est un comportement défini par l'implémentation (6.5.7). Common est décalé avec l'extension de signe, ce qui donnerait le résultat -2^(31-n), qui est ensuite interprété comme unsigned int avec la valeur 2^32 - 2^(31-n) par le spécificateur de conversion printf%x.

+0

est ~ 0 le signe ou non signé ... – shirley

+0

'0' est représentable comme un' int', donc le type de '~ 0' est' int' aussi. –

1

Lorsque x = 0x80000000, ~ (x + 0xffffffff) = 0x8000000, ~ x + 1 = 0x80000000,

Sur un système à 32 bits int (en supposant que x est de type int) et la représentation signée du complément à deux, cette expression:

~x+1 

est un comportement indéfini. x = 0x80000000 signifie ~x == 0x7FFFFFFF == INT_MAX et INT_MAX + 1 est un comportement indéfini. Donc, ~x + 1 peut être 0x80000000 ou toute autre chose.

Cette expression:

~(x+0xffffffff) 

d'autre part, est définie (0xffffffff est unsigned int en C) et est égale à 0x80000000. Il est en fait défini car 0xffffffff est unsigned int et les entiers non signés ne débordent jamais au sens de la norme C.

Cela signifie que cette déclaration:

printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n)); 

invoque un comportement non défini et il n'a pas de sens de comparer les résultats.

0

(en supposant que sizeof (int) vaut 4, c'est-à-dire une valeur signée de 32 bits). 0x80000000; // -2147483648 qui est le plus petit possible négatif int 0xFFFFFFFF // est -1

Ajout les deux causes ensemble un « enrouler autour » du négatif au positif 0x7FFFFFFF est la somme des deux (en utilisant l'arithmétique int), qui est 2147483647

Utilisation de l'opérateur « ~ » sur 0x7FFFFFFF donne un complétent sage peu ou 0x80000000

Si vous commencez avec une valeur int et soustrayez 1 de celui-ci (ou ajouter 1 à, il ne importe) assez de fois, vous le ferez retourner son signe. C'est un problème de base avec l'arithmétique en utilisant une précision fixe.

Dans votre cas, vous ne pouvez pas espérer mélanger des opérateurs arithmétiques et binaires signés sans être très attentif à ce cas limite.Notez également qu'il existe une asymétrie lors de l'utilisation de l'arithmétique du complément à 2: il y a un nombre négatif plus que positif (car vous devez représenter zéro, ce qui laisse un nombre impair de représentations d'autres bits pour le reste des valeurs).

Questions connexes