Opérateurs au niveau du bit et opérateurs de décalage (référence C#)

Les opérateurs au niveau du bit et de décalage incluent le complément de bits unaire, les décalages binaires vers la gauche et la droite, le décalage vers la droite non signé, et les opérateurs logiques binaires AND, OR et OR exclusif. Ces opérandes prennent des opérandes des types numériques intégraux ou du type char.

Ces opérateurs sont définis pour les types int, uint, long et ulong. Lorsque les deux opérandes sont d’autres types intégraux (sbyte, byte, short, ushort ou char), leurs valeurs sont converties en valeurs de type int, qui est également le type de résultat d’une opération. Lorsque les opérandes sont de différents types intégraux, leurs valeurs sont converties vers le type intégral le plus proche. Pour plus d’informations, consultez la section Promotions numériques de la spécification du langage C#. Les opérateurs composés (tels que >>=) ne convertissent pas leurs arguments en int et n’ont pas le type de résultat int.

Les opérateurs &, | et ^ sont également définis pour les opérandes du type bool. Pour plus d’informations, consultez Opérateurs logiques booléens.

Les opérations de décalage et au niveau du bit ne provoquent jamais de dépassements de capacité et donnent les mêmes résultats dans des contextes checked et unchecked.

Opérateur de complément de bits ~

L’opérateur ~ produit un complément de bits de son opérande en inversant chaque bit :

uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Console.WriteLine(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011

Vous pouvez également utiliser le symbole ~ pour déclarer des finaliseurs. Pour plus d’informations, consultez Finaliseurs.

Opérateur de décalage gauche <<

L’opérateur << décale son opérande de partie gauche vers le nombre de bits spécifié par son opérande de partie droite. Pour obtenir des informations sur la façon dont l’opérande droit définit la valeur de décalage, consultez la section Valeur de décalage des opérateurs de décalage.

L’opération de décalage gauche supprime les bits d’ordre supérieur qui sont en dehors de la plage du type de résultat, et définit les positions de bits vides d’ordre inférieur sur zéro, comme le montre l’exemple suivant :

uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2)}");

uint y = x << 4;
Console.WriteLine($"After:  {Convert.ToString(y, toBase: 2)}");
// Output:
// Before: 11001001000000000000000000010001
// After:  10010000000000000000000100010000

Étant donné que les opérateurs de décalage sont définis uniquement pour les types int, uint, long et ulong, le résultat d’une opération contient toujours au moins 32 bits. Si l’opérande de partie gauche est d’un autre type intégral (sbyte, byte, short, ushort ou char), sa valeur est convertie en type int, comme l’indique l’exemple suivant :

byte a = 0b_1111_0001;

var b = a << 8;
Console.WriteLine(b.GetType());
Console.WriteLine($"Shifted byte: {Convert.ToString(b, toBase: 2)}");
// Output:
// System.Int32
// Shifted byte: 1111000100000000

Opérateur de décalage vers la droite >>

L’opérateur >> décale son opérande de partie gauche vers le nombre de bits défini par son opérande de partie droite. Pour obtenir des informations sur la façon dont l’opérande droit définit la valeur de décalage, consultez la section Valeur de décalage des opérateurs de décalage.

L’opération de décalage vers la droite ignore les bits d’ordre inférieur, comme le montre l’exemple suivant :

uint x = 0b_1001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2), 4}");

uint y = x >> 2;
Console.WriteLine($"After:  {Convert.ToString(y, toBase: 2).PadLeft(4, '0'), 4}");
// Output:
// Before: 1001
// After:  0010

Les positions de bits vides d’ordre supérieur sont définies en fonction du type de l’opérande de partie gauche comme suit :

  • Si l’opérande gauche est de type int ou long, l’opérateur de décalage vers la droite effectue un décalage arithmétique : la valeur du bit le plus significatif (le bit de signe) de l’opérande gauche est propagée vers les positions des bits vides de poids fort. Autrement dit, les positions de bits vides d’ordre supérieur sont définies sur zéro si l’opérande de partir gauche n’est pas négatif et sur un s’il est négatif.

    int a = int.MinValue;
    Console.WriteLine($"Before: {Convert.ToString(a, toBase: 2)}");
    
    int b = a >> 3;
    Console.WriteLine($"After:  {Convert.ToString(b, toBase: 2)}");
    // Output:
    // Before: 10000000000000000000000000000000
    // After:  11110000000000000000000000000000
    
  • Si l’opérande gauche est de type uint ou ulong, l’opérateur de décalage vers la droite effectue un décalage logique : les positions des bits vides de poids fort sont toujours définies sur zéro.

    uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000;
    Console.WriteLine($"Before: {Convert.ToString(c, toBase: 2), 32}");
    
    uint d = c >> 3;
    Console.WriteLine($"After:  {Convert.ToString(d, toBase: 2).PadLeft(32, '0'), 32}");
    // Output:
    // Before: 10000000000000000000000000000000
    // After:  00010000000000000000000000000000
    

Notes

Utilisez l’opérateur de décalage vers la droite non signé pour effectuer un décalage logique sur les opérandes de types entiers signés. Cela est préférable au cast d’un opérande gauche en type non signé, puis au cast du résultat d’une opération de décalage en type signé.

Opérateur de décalage vers la droite non signé >>>

Disponible en C# 11 et versions ultérieures, l’opérateur >>> décale son opérande gauche vers la droite du nombre de bits défini par son opérande droit. Pour obtenir des informations sur la façon dont l’opérande droit définit la valeur de décalage, consultez la section Valeur de décalage des opérateurs de décalage.

L’opérateur >>> effectue toujours un décalage logique. Autrement dit, les positions de bits vides de poids fort sont toujours définies sur zéro, quel que soit le type de l’opérande gauche. L’opérateur >> effectue un décalage arithmétique (autrement dit, la valeur du bit le plus significatif est propagée aux positions de bits vides de poids fort) si l’opérande gauche est d’un type signé. L’exemple suivant illustre la différence entre les opérateurs >> et >>> pour un opérande gauche négatif :

int x = -8;
Console.WriteLine($"Before:    {x,11}, hex: {x,8:x}, binary: {Convert.ToString(x, toBase: 2), 32}");

int y = x >> 2;
Console.WriteLine($"After  >>: {y,11}, hex: {y,8:x}, binary: {Convert.ToString(y, toBase: 2), 32}");

int z = x >>> 2;
Console.WriteLine($"After >>>: {z,11}, hex: {z,8:x}, binary: {Convert.ToString(z, toBase: 2).PadLeft(32, '0'), 32}");
// Output:
// Before:             -8, hex: fffffff8, binary: 11111111111111111111111111111000
// After  >>:          -2, hex: fffffffe, binary: 11111111111111111111111111111110
// After >>>:  1073741822, hex: 3ffffffe, binary: 00111111111111111111111111111110

Opérateur AND logique &

L’opérateur & calcule le AND logique au niveau du bit de ses opérandes intégraux :

uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000

Pour les opérandes bool, l’opérateur & calcule le AND logique de ses opérandes. L’opérateur unaire & est l’opérateur address-of.

L’opérateur OR exclusif logique ^

L’opérateur ^ calcule le OR exclusif logique au niveau du bit, également appelé XOR logique au niveau du bit, de ses opérandes intégraux :

uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100

Pour les opérandes bool, l’opérateur ^ calcule le OR exclusif logique de ses opérandes.

L’opérateur OU logique |

L’opérateur | calcule le OR logique au niveau du bit de ses opérandes intégraux :

uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001

Pour les opérandes bool, l’opérateur | calcule le OR logique de ses opérandes.

Assignation composée

Pour un opérateur binaire op, une expression d’assignation composée du formulaire

x op= y

équivaut à :

x = x op y

sauf que x n’est évalué qu’une seule fois.

L’exemple suivant montre l’utilisation de l’assignation composée avec des opérateurs de décalage et des opérateurs au niveau du bit :

uint INITIAL_VALUE = 0b_1111_1000;

uint a = INITIAL_VALUE;
a &= 0b_1001_1101; 
Display(a);  // output: 10011000

a = INITIAL_VALUE;
a |= 0b_0011_0001; 
Display(a);  // output: 11111001

a = INITIAL_VALUE;
a ^= 0b_1000_0000;
Display(a);  // output: 01111000

a = INITIAL_VALUE;
a <<= 2;
Display(a);  // output: 1111100000

a = INITIAL_VALUE;
a >>= 4;
Display(a);  // output: 00001111

a = INITIAL_VALUE;
a >>>= 4;
Display(a);  // output: 00001111

void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2).PadLeft(8, '0'), 8}");

En raison des promotions numériques, le résultat de l’opération op risque de ne pas être implicitement convertible en type T de x. Dans ce cas, si op est un opérateur prédéfini et que le résultat de l’opération est explicitement convertible en type T de x, une expression d’assignation composée de la forme x op= y équivaut à x = (T)(x op y), sauf que x n’est évalué qu’une seule fois. L’exemple suivant illustre ce comportement :

byte x = 0b_1111_0001;

int b = x << 8;
Console.WriteLine($"{Convert.ToString(b, toBase: 2)}");  // output: 1111000100000000

x <<= 8;
Console.WriteLine(x);  // output: 0

Priorité des opérateurs

La liste suivante présente les opérateurs au niveau du bit et les opérateurs de décalage par ordre de précédence, de la plus élevée à la plus basse :

  • Opérateur de complément de bits ~
  • Opérateurs de décalage <<, >> et >>>
  • L’opérateur AND logique &
  • Opérateur OR exclusif logique ^
  • Opérateur OR logique |

Utilisez des parenthèses, (), pour modifier l’ordre d’évaluation imposé par la précédence des opérateurs :

uint a = 0b_1101;
uint b = 0b_1001;
uint c = 0b_1010;

uint d1 = a | b & c;
Display(d1);  // output: 1101

uint d2 = (a | b) & c;
Display(d2);  // output: 1000

void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2), 4}");

Pour obtenir la liste complète des opérateurs C# classés par niveau de priorité, consultez la section Priorité des opérateurs de l’article Opérateurs C#.

Valeur de décalage des opérateurs de décalage

Pour les opérateurs de décalage intégrés <<, >> et >>>, le type de l’opérande droit doit être int ou un type ayant une conversion numérique implicite prédéfinie sur int.

Pour les expressions x << count, x >> count et x >>> count, la valeur de décalage réelle dépend du type de x, comme suit :

  • Si le type de x est int ou uint, la valeur de décalage est définie par les cinq bits de poids faible de l’opérande droit. La valeur de décalage est donc calculée à partir de count & 0x1F (ou de count & 0b_1_1111).

  • Si le type de x est long ou ulong, la valeur de décalage est définie par les six bits de poids faible de l’opérande droit. La valeur de décalage est donc calculée à partir de count & 0x3F (ou de count & 0b_11_1111).

L’exemple suivant illustre ce comportement :

int count1 = 0b_0000_0001;
int count2 = 0b_1110_0001;

int a = 0b_0001;
Console.WriteLine($"{a} << {count1} is {a << count1}; {a} << {count2} is {a << count2}");
// Output:
// 1 << 1 is 2; 1 << 225 is 2

int b = 0b_0100;
Console.WriteLine($"{b} >> {count1} is {b >> count1}; {b} >> {count2} is {b >> count2}");
// Output:
// 4 >> 1 is 2; 4 >> 225 is 2

int count = -31;
int c = 0b_0001;
Console.WriteLine($"{c} << {count} is {c << count}");
// Output:
// 1 << -31 is 2

Notes

Comme le montre l’exemple précédent, le résultat d’une opération de décalage peut être différent de zéro, même si la valeur de l’opérande droit est supérieure au nombre de bits dans l’opérande gauche.

Opérateurs logiques d’énumération

Les opérateurs ~, &, | et ^ sont également pris en charge par tout type d’énumération. Pour les opérandes du même type énumération, une opération logique est effectuée sur les valeurs correspondantes du type intégral sous-jacent. Par exemple, pour tout x et y d’un type énumération T avec un type sous-jacent U, l’expression x & y produit le même résultat que l’expression (T)((U)x & (U)y).

Vous utilisez généralement des opérateurs logiques au niveau du bit avec un type énumération qui est défini à l’aide de l’attribut Flags. Pour plus d’informations, consultez la section Types énumération comme indicateurs binaires de l’articleTypes énumération.

Capacité de surcharge de l’opérateur

Un type défini par l’utilisateur peut surcharger les opérateurs ~, <<, >>, >>>, &, | et ^. Quand un opérateur binaire est surchargé, l’opérateur d’assignation composée correspondant est aussi implicitement surchargé. Un type défini par l’utilisateur ne peut pas surcharger explicitement un opérateur d’assignation composée.

Si un type défini par l’utilisateur T surcharge l’opérateur <<, >> ou >>>, le type de l’opérande gauche doit être T. En C# 10 et versions antérieures, le type de l’opérande droit doit être int. Depuis C# 11, l’opérande droit d’un opérateur de décalage surchargé peut être d’un type quelconque.

spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Voir aussi