Décalage arithmétique sur un entier signé

J’essaie de comprendre comment fonctionnent exactement les opérateurs de décalage arithmétique en C, et comment cela affectera les entiers 32 bits signés.

Pour simplifier les choses, disons que nous travaillons dans un octet (8 bits):

x = 1101.0101 MSB[ 1101.0101 ]LSB 

En lisant d’autres articles sur Stack Overflow et certains sites Web, j’ai constaté que: << passera à MSB (à gauche dans mon cas) et remplira les bits LSB «vides» avec des 0.

Et >> passera à LSB (à droite, dans mon cas) et remplira les bits “vides” avec le bit MS

Donc, x = x << 7 aura pour effet de déplacer LSB vers MSB et de tout régler à 0s.

 1000.0000 

Maintenant, disons que je voudrais >> 7 , dernier résultat. Cela se traduirait par [0000.0010] ? Ai-je raison?

Ai-je raison sur mes hypothèses concernant les opérateurs postés?

Je viens de tester sur ma machine, **

 int x = 1; //000000000......01 x = x <> 31; //111111111......11 (Everything is filled with 1s !!!!!) 

Pourquoi?

Le décalage à droite d’un nombre signé négatif a un comportement défini par la mise en œuvre.

Si vos 8 bits sont censés représenter une valeur de 8 bits signée (comme vous parlez d’un «entier 32 bits signé» avant de passer à des exemples de 8 bits), vous avez un nombre négatif. Le déplacer vers la droite peut remplir des bits “vides” avec le MSB d’origine (c’est-à-dire effectuer une extension de signe) ou il peut changer de zéros, selon la plate-forme et / ou le compilateur.

(Le comportement défini par l’implémentation signifie que le compilateur fera quelque chose de sensible, mais d’une manière dépendante de la plate-forme; la documentation du compilateur est censée vous dire quoi.)


Un décalage vers la gauche, si le nombre est négatif, ou le décalage décalé de 1 vers le bit de signe ou au-delà, a un comportement indéfini (comme la plupart des opérations sur des valeurs signées qui provoquent un débordement).

(Un comportement non défini signifie que tout peut arriver.)


Les mêmes opérations sur les valeurs non signées sont bien définies dans les deux cas: les bits “vides” seront remplis avec 0.

Les opérations de décalage binary ne sont pas définies pour les valeurs négatives

pour ‘<<'

6.5.7 / 4 […] Si E1 a un type signé et une valeur non négative et E1 × 2 E2 est représentable dans le type de résultat, alors c’est la valeur résultante; sinon, le comportement est indéfini.

et pour ‘>>’

6.5.7 / 5 […] Si E1 a un type signé et une valeur négative, la valeur résultante est définie par l’implémentation.

C’est une perte de temps d’étudier le comportement de ces opérations sur des nombres signés sur une implémentation spécifique, car vous n’avez aucune garantie que cela fonctionne de la même manière sur toute autre implémentation (une implémentation est par exemple un compilateur sur votre ordinateur avec votre parameters de ligne de commande spécifiques).

Cela pourrait même ne pas fonctionner pour une version plus ancienne ou plus récente du même compilateur. Le compilateur peut même définir ces bits comme aléatoires ou indéfinis. Cela signifierait que la même séquence de code pourrait produire des résultats totalement différents lorsqu’elle est utilisée dans vos sources ou même dépendre de choses telles que l’optimisation de l’assemblage ou l’utilisation d’autres registres. S’il est encapsulé dans une fonction, il peut même ne pas produire le même résultat sur ces bits lors de deux appels consécutifs avec les mêmes arguments.

En considérant uniquement les valeurs non négatives , l’effet du décalage gauche de 1 ( expression << 1 ) est le même que celui de l'expression multiple (à condition que l'expression * 2 ne déborde pas) et l'effet du décalage droit de 1 ( expression >> 1 ) est la même chose que diviser par 2.

Comme d’autres, le décalage de valeur négative est défini par la mise en œuvre.

La plupart des implémentations traitent le décalage à droite signé comme plancher (x / 2 N ) en remplissant les bits décalés à l’aide du bit de signe. C’est très pratique dans la pratique, car cette opération est si courante. Par contre, si vous déplacez un entier non signé à droite, les bits décalés seront mis à zéro.

Du sharepoint vue de la machine, la plupart des implémentations disposent de deux types d’instructions shift-right:

  1. Un changement arithmétique correct (ayant souvent des mnémoniques ASR ou SRA) qui fonctionne comme je l’ai expliqué.

  2. Un changement de logique “right” (oftem ayant mnemonic LSR ou SRL ou SR) qui fonctionne comme prévu.

La plupart des compilateurs utilisent d’abord les types signés et les deuxièmes les non signés. Juste pour plus de commodité.

Dans le compilateur 32 bits

x = x >> 31;

ici x est l’entier signé, donc le 32ème bit est le bit de signe.

La valeur finale x est 100000 … 000 . et 32ème bit indique une valeur.

ici x valeur mise en œuvre à 1 compliment.

alors x final est -32768