Opérateurs de décalage de base << et >>

    Les opérateurs << et >> sont des opérateurs binaires, décrits dans la Norme ISO, 5.8. Ils agissent sur des opérandes de type entier auxquels sont appliquées les promotions entières. Le résultat est du type de l'opérande de gauche après promotion. Le résultat est indéfini si l'opérande de droite est négatif, ou supérieur ou égal au nombre de bits nécessaires à la représentation du type de l'expression de gauche.

Décalage à gauche

    La valeur de E1 << E2 est E1 (interprété comme une succession de bits) décalé vers la gauche de E2 positions binaires, les positions libérées à droite étant remplies de zéros.


    Supposons qu'un unsigned int soit codé sur un octet, donc UINT_MAX+1 = 256
 
unsigned E1 = 254;            // Affichage :
cout << (E1 << 3) << endl;    // 240
int E2 = 15;
cout << (E2 << 3) << endl;    // 120
int E3 = 127;
cout << (E3 << 3) << endl;    // -8

    En effet, E1 est codé 1111 1110, donc E1 << 3 est codé 1111 0000, où les trois positions de droite libérées par le décalage à gauche, sont remplies de zéros. La valeur entière non signée décimale correspondante est 240. Or 254 * 8 = 2032, et 2032 mod 256 = 240.

    E2 est codé 0000 1111, donc E2 << 3 est codé 0111 1000. La valeur entière signée décimale correspondante est 120. Or 15 * 8 = 120.

    E3 est codé 0111 1111, donc E2 << 3 est codé 1111 1000. La valeur entière signée décimale correspondante est -8. Il y a dépassement de capacité

Décalage à droite

    La valeur de E1 >> E2 est E1 décalé vers la droite de E2 positions binaires.

Exemples d'utilisation

    Dans de nombreux langages d'assemblage existenr les opérations de décalage circulaire, à gauche ou à droite, où les bits qui disparaissent d'un coté réapparaissent de l'autre. Ces instructions n'existent pas en C++, mais pourraient être implémentées par les fonctions génériques cshl() (circular shift left) et cshr() (circular shift right) suivantes :
 
template <typename T> T cshl (T Op1, unsigned char Op2)
{
    if (!Op2) return Op1;

    // Les décalages à droite dépendent de l'implémentation lorsque le premier
    //   opérande est d'un type signé et de valeur négative
    // Son bit de signe est donc récupéré et décalé à part, et forcé à 0 dans
    // le premier opérande ==> le décalage à droite ne pose jamais de problème.

    unsigned long BitSigne = (1 << ((sizeof (Op1) << 3) - 1)) & Op1;
    Op1 = (Op1 & ~BitSigne);

    // Décalage à gauche

    return (Op1 << Op2) |

           // Décalage à droite de la partie gauche qui sort

           (Op1 >> ((sizeof (Op1) << 3) - Op2)) |

           // Placement du bit de signe

           (BitSigne >> ((sizeof (Op1) << 3) - Op2));

} // cshl()

template <typename T> T cshr (T Op1, unsigned char Op2)
{
    if (!Op2) return Op1;
    
    // Les décalages à droite dépendent de l'implémentation lorsque le premier
    //   opérande est d'un type signé et de valeur négative
    // Son bit de signe est donc récupéré et décalé à part, et forcé à 0 dans
    // le premier opérande ==> le décalage à droite ne pose jamais de problème.
           
    unsigned long BitSigne = (1 << ((sizeof (Op1) << 3) - 1)) & Op1;
    Op1 = (Op1 & ~BitSigne);

    // Décalage à droite
           
    return (Op1 >> Op2) |
           
           // Décalage à gauche de la partie droite qui sort

           (Op1 << (((sizeof (Op1) << 3) - 1) - Op2 + 1)) |
           
           // Placement du bit de signe

           (BitSigne >> Op2);

} // cshr()

Surcharge des opérateurs << et >> comme injecteurs ou extracteurs

 

Surcharge des opérateurs << et >> comme méthodes de classes


[1] définie dans <climits>     L'opérateur << ne peut être membre d'une classe puisque son premier paramètre (opérande gauche de l'opérateur binaire) doit être un flux de sortie. Il est donc nécessaire de le déclarer ami de la classe s'il doit acccéder aux données membres privées ou protégées.

Exemple

class CPoint
{
  public :
    // ..
    friend ostream & operator << (ostream & os, const CPoint & Point);

}; // CPoint

inline ostream & CPoint::operator << (ostream & os, const CPoint & Point)
{
    return os << '[' << m_X << ", " << m_Y << ']';

} // <<

Sommaire

Utilisation

CPoint P1 (10, 10);
CPoint P2;
// ...                   Affichage
cout << P1 << endl;   // [10, 10]
cerr << P2 << endl;   // [0, 0]