web-dev-qa-db-fra.com

Comportement indéfini du décalage à droite en C ++

De cppreference.com:

Pour a non signé et pour a signé avec des valeurs non négatives, la valeur de a >> b est la partie entière de a/2b . Pour a négatif, la valeur de a >> b est définie par l'implémentation (dans la plupart des implémentations, cela effectue un décalage arithmétique vers la droite, de sorte que le résultat reste négatif).

Dans tous les cas, si la valeur de l'opérande droit est négative ou est supérieure ou égale au nombre de bits dans l'opérande gauche promu, le comportement n'est pas défini.

Pourquoi avons-nous un comportement indéfini au cas où l'opérande droit est supérieur ou égal au nombre de bits dans l'opérande gauche promu?
Il me semble que le résultat devrait être 0 (au moins pour les entiers non signés/positifs) ...

En particulier, avec g ++ (version 4.8.4, Ubuntu):

unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;

donne: 0 1

14
R2B2

L'un des objectifs du C++ est de permettre un code rapide et efficace, "proche du matériel". Et sur la plupart des matériels, un décalage à droite ou à gauche entier peut être implémenté par un seul opcode. Le problème est que différents processeurs ont un comportement différent dans ce cas où la magnitude de décalage est supérieure au nombre de bits.

Donc, si C++ imposait un comportement particulier pour les opérations de décalage, lors de la production de code pour un processeur dont le comportement opcode ne correspond pas à toutes les exigences de la norme, les compilateurs devraient insérer des vérifications et une logique pour s'assurer que le résultat est tel que défini par la norme dans tous cas. Cela devrait arriver à presque toutes les utilisations des opérateurs de changement de vitesse intégrés, à moins qu'un optimiseur ne prouve que le cas du coin ne se produira pas réellement. Les contrôles et la logique ajoutés ralentiraient potentiellement le programme.

31
aschepler

Pour donner un exemple spécifique, x86 réduit le nombre de décalages à 5 bits (6 bits pour les décalages de 64 bits), tandis que ARM réduit le nombre de décalages à 8 bits. Avec la norme C++ actuelle, les compilateurs pour les deux processeurs peuvent implémenter des décalages avec un seul opcode.

Si la norme C++ devait définir le résultat des décalages de plus que la longueur de l'opérande d'une manière particulière, les compilateurs ciblant au moins une des familles de CPU (et peut-être les deux, si le résultat requis par C++ ne correspondait à aucune des implémentations matérielles, comme le comportement que vous suggérez) devrait implémenter chaque opération de décalage en utilisant des branches qui produiraient le résultat requis là où l'opcode CPU ne le ferait pas.

1
Dmitry Grigoryev