32 votes

Un décalage arithmétique à droite donne un résultat faux?

Je dois être absolument fou ici, mais gcc 4.7.3 sur ma machine donne le résultat le plus absurde. Voici le code exact que je teste:

 #include <iostream>

using namespace std;

int main(){
  unsigned int b = 100000;
  cout << (b>>b) << endl;
  b = b >> b;
  cout << b << endl;
  b >>= b;
  cout << b << endl;
  return 0;
}
 

Maintenant, tout nombre décalé vers la droite devrait entraîner 0 ( n/(2^n) == 0 avec une division entière, n> 1 et positif / non signé), mais voici ma sortie:

 100000
100000
100000
 

Suis-je fou? Que pourrait-il se passer?

49voto

davmac Points 4317

En C++ comme en C, les changements sont limitées à la taille (en bits) de la valeur a changé. Par exemple, si unsigned int de 32 bits, puis un déplacement de plus de 31 n'est pas défini.

Dans la pratique, cela signifie que si le compilateur peut déterminer au moment de la compilation que le décalage est trop grand, il peut choisir de ne pas effectuer le déplacement à tous (en fait, il peut produire du code qui n'a à peu près tout, mais c'est une pratique courant résultat). Un autre résultat est que le 5 le moins significatif de bits de décalage sont utilisés, et le plus élevé de bits d'ordre sont ignorées; cela est dû au compilateur produisant une instruction machine qui ne fait que cela (par exemple SHR sur l'architecture x86).

Références:

Pour C, N1570 section 6.5.7:

Si la valeur de l'opérande de droite est négatif ou supérieur ou égale à la largeur de la promotion opérande de gauche, le comportement est undefined.

Pour C++, N3690 la section 5.8, "[expr.maj]":

Le comportement est indéfini si l'opérande de droite est négatif, ou plus inférieure ou égale à la longueur en bits de l'promu opérande de gauche.

N1570 est un projet, presque identique à la sortie de l'ISO C11 standard; cette clause a été à peu près la même depuis 1989, dans le C ANSI standard.

N3690 est un récent projet de la norme C++, je ne suis pas sûr de savoir si c'est le meilleur à utiliser, mais encore une fois, cette clause n'a pas changé.

32voto

Shafik Yaghmour Points 42198

Vous êtes en invoquant un comportement indéfini si vous passez le plus de la longueur en bits de l'opérande de gauche, le projet de norme C++ section 5.8 d'opérateurs de Décalage de l'alinéa 1 dit: (c'est moi qui souligne):

Les opérandes doivent être partie intégrante ou non délimité de type énumération et fait partie intégrante des promotions sont effectuées. Le type du résultat est celui de la promotion opérande de gauche. Le comportement est indéfini si l'opérande de droite est négatif, ou supérieure ou égale à la longueur en bits de l'promu opérande de gauche.

Intéressant de noter que les deux gcc et clang peut générer un avertissement pour ce code si le décalage si un littéral:

cout << (b>> 100000) ;

ou si b est un const, l'avertissement pour gcc est comme suit:

warning: right shift count >= width of type [enabled by default]

comme MSalters points dans les commentaires à la question, nous pourrions ne pas être en mesure de même compter sur cet avertissement car c'est un comportement indéfini, ce qui est cohérent avec les normes de la note sur le comportement non défini dans les termes et définitions l'article qui dit:

Remarque: [...] Admissible comportement indéfini plages d'ignorer la situation complètement avec des résultats imprévisibles, à se comporter lors de la traduction ou de l'exécution du programme dans documenté de façon caractéristique de l'environnement (avec ou sans émission d'un message de diagnostic), à la terminaison d'une traduction ou d'exécution (avec l'émission d'un message de diagnostic). [...]

Plate-forme des détails spécifiques

Une explication possible de l'absence apparente d'un changement dans l'exemple de code peut-être parce que, sur certaines plateformes, le décalage sera masqué à l' 5 bits par exemple sur un x86 architecture, nous pouvons voir l' Intel® 64 et IA-32 Architectures Développeur de Logiciels Manuel de l' article SAL/SAR/SHL/SHR-Changement dans l' Architecture IA-32 Compatibilité de l'article dit:

Le 8086 ne masque pas le décalage. Cependant, tous les autres IA-32 processeurs (en commençant avec l'Intel 286) ne masque le décalage de 5 bits, résultant en un nombre maximal de 31. [...]

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