Delen via


Bitwise- en shiftoperators (C#-verwijzing)

De bitsgewijze operatoren en shifts bevatten een ongewijze aanvulling op bitgewijze aanvulling, binaire shift naar links en rechts, niet-ondertekende rechter shift, en de binaire logische AND, OR en exclusieve OR-operators. Deze operanden nemen operanden van de integrale numerieke typen of het tekentype .

Deze operatoren worden gedefinieerd voor de inttypen , uinten ulong longtypen. Wanneer beide operanden van andere integrale typen zijn (sbyte, byte, short, ushortof char), worden de waarden geconverteerd naar het int type, wat ook het resultaattype van een bewerking is. Wanneer operanden van verschillende integrale typen zijn, worden hun waarden geconverteerd naar het dichtstbijzijnde integrale type. Zie de sectie Numerieke promoties van de C#-taalspecificatie voor meer informatie. De samengestelde operators (zoals >>=) converteren hun argumenten niet naar int of hebben het resultaattype als int.

De &operatoren , |en ^ operatoren worden ook gedefinieerd voor operanden van het bool type. Zie Booleaanse logische operators voor meer informatie.

Bitwise en shift-bewerkingen veroorzaken nooit overloop en produceren dezelfde resultaten in gecontroleerde en niet-gecontroleerde contexten.

Bitsgewijze complementoperator ~

De ~ operator produceert een bitsgewijze aanvulling van de operand door elke bit om te draaien:

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

U kunt ook het ~ symbool gebruiken om finalizers te declareren. Zie Finalizers voor meer informatie.

Operator voor linkerdienst <<

De << operator verschuift de linkeroperand naar links door het aantal bits dat is gedefinieerd door de rechteroperand. Zie het aantal diensten van de sectie Shift-operatoren voor informatie over hoe de rechteroperand het aantal diensten definieert.

Met de bewerking links verplaatsen worden de bits met hoge volgorde verwijderd die buiten het bereik van het resultaattype vallen en worden de lege bitposities met lage volgorde ingesteld op nul, zoals in het volgende voorbeeld wordt weergegeven:

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

Omdat de shiftoperators alleen zijn gedefinieerd voor de inttypenlonguintulong, bevat het resultaat van een bewerking altijd ten minste 32 bits. Als de linkeroperand van een ander integraal type (sbyte, byte, ushortshortofchar) is, wordt de waarde ervan geconverteerd naar het int type, zoals in het volgende voorbeeld wordt weergegeven:

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

Operator voor rechter shift >>

De >> operator verschuift de linkeroperand naar rechts door het aantal bits dat is gedefinieerd door de rechteroperand. Zie het aantal diensten van de sectie Shift-operatoren voor informatie over hoe de rechteroperand het aantal diensten definieert.

Met de right-shift-bewerking worden de bits met lage volgorde verwijderd, zoals in het volgende voorbeeld wordt weergegeven:

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

De lege bitposities in hoge volgorde worden als volgt ingesteld op basis van het type linkeroperand:

  • Als de linkeroperand van het type int is of long, voert de operator voor de rechter shift een rekenkundige verschuiving uit: de waarde van de meest significante bit (de tekenbit) van de linkeroperand wordt doorgegeven aan de lege bitposities in hoge volgorde. Dat wil gezegd: de lege bitposities in hoge volgorde worden ingesteld op nul als de linkeroperand niet-negatief is en is ingesteld op één als deze negatief is.

    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
    
  • Als de linkeroperand van het type uint is of ulong, voert de operator van rechts-shift een logische verschuiving uit: de lege bitposities in hoge volgorde worden altijd ingesteld op nul.

    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
    

Notitie

Gebruik de niet-ondertekende operator voor rechtse shift om een logische shift uit te voeren op operanden van ondertekende gehele getallen. Dit is de voorkeur om een linkeroperand naar een niet-ondertekend type te casten en vervolgens het resultaat van een dienstbewerking terug te gieten naar een ondertekend type.

Unsigned right-shift operator >>>

De operator is beschikbaar in C# 11 en hoger en verplaatst de >>> linkeroperand naar rechts door het aantal bits dat is gedefinieerd door de rechteroperand. Zie het aantal diensten van de sectie Shift-operatoren voor informatie over hoe de rechteroperand het aantal diensten definieert.

De >>> operator voert altijd een logische verschuiving uit. Dat wil gezegd: de lege bitposities in hoge volgorde worden altijd ingesteld op nul, ongeacht het type van de linkeroperand. De >> operator voert een rekenkundige verschuiving uit (dat wil gezegd, de waarde van de meest significante bit wordt doorgegeven aan de lege bitposities in hoge volgorde) als de linkeroperand van een ondertekend type is. In het volgende voorbeeld ziet u het verschil tussen >> en >>> operators voor een negatieve operand aan de linkerkant:

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

Logische AND-operator &

De & operator berekent de bitsgewijze logische EN van de bijbehorende integrale operanden:

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

Voor bool operanden berekent de & operator de logische EN van de operanden. De unaire & operator is het adres van de operator.

Logische exclusieve OR-operator ^

De ^ operator berekent de bitwise logische exclusieve OR, ook wel de bitwise logische XOR genoemd, van de integrale operanden:

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

Voor bool operanden berekent de ^ operator de logische exclusieve OF van de operanden.

Logische OF-operator |

De | operator berekent de bitsgewijze logische OR van de bijbehorende integrale operanden:

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

Voor bool operanden berekent de | operator de logische OR van de operanden.

Samengestelde toewijzing

Voor een binaire operator op, een samengestelde toewijzingsexpressie van het formulier

x op= y

is gelijk aan

x = x op y

behalve dat dit x slechts eenmaal wordt geëvalueerd.

In het volgende voorbeeld ziet u het gebruik van samengestelde toewijzingen met bitsgewijze operatoren en shiftoperators:

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}");

Vanwege numerieke promoties is het resultaat van de op bewerking mogelijk niet impliciet converteerbaar naar het type T x. In dat geval op is een vooraf gedefinieerde operator en het resultaat van de bewerking expliciet converteerbaar naar het type T x, is een samengestelde toewijzingsexpressie van het formulier x op= y gelijk aan x = (T)(x op y), behalve dat het x slechts eenmaal wordt geëvalueerd. In het volgende voorbeeld ziet u dat gedrag:

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

Operatorprioriteit

In de volgende lijst worden bitsgewijze operatoren geordeld en worden operatoren verplaatst vanaf de hoogste prioriteit tot de laagste:

  • Bitsgewijze complementoperator ~
  • Shift-operatoren <<, >>en >>>
  • Logische AND-operator &
  • Logische exclusieve OR-operator ^
  • Logische OF-operator |

Gebruik haakjes, ()om de volgorde van evaluatie te wijzigen die wordt opgelegd door de prioriteit van de operator:

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}");

Zie de sectie Operatorprioriteit van het artikel C#-operators voor de volledige lijst met C#-operators die zijn gerangschikt op prioriteitsniveau.

Aantal shifts van de shiftoperators

Voor de x << count, x >> counten x >>> count expressies is het werkelijke aantal diensten afhankelijk van x het type als volgt:

  • Als het type x is int ofuint, wordt het aantal diensten gedefinieerd door de vijf bits met lage volgorde van de rechteroperand. Dat wil gezegd, het aantal diensten wordt berekend van count & 0x1F (of count & 0b_1_1111).

  • Als het type x is long of ulong, wordt het aantal diensten gedefinieerd door de lage volgorde zes bits van de rechteroperand. Dat wil gezegd, het aantal diensten wordt berekend van count & 0x3F (of count & 0b_11_1111).

In het volgende voorbeeld ziet u dat gedrag:

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

Notitie

Zoals in het voorgaande voorbeeld wordt weergegeven, kan het resultaat van een dienstbewerking niet nul zijn, zelfs als de waarde van de rechteroperand groter is dan het aantal bits in de linkeroperand.

Logische operators inventariseren

De ~operators , &en |^ operators worden ook ondersteund door elk opsommingstype. Voor operanden van hetzelfde opsommingstype wordt een logische bewerking uitgevoerd op de bijbehorende waarden van het onderliggende integrale type. Voor een x en y van een opsommingstype T met een onderliggend type Uproduceert de x & y expressie bijvoorbeeld hetzelfde resultaat als de (T)((U)x & (U)y) expressie.

Normaal gesproken gebruikt u bitwise logische operators met een opsommingstype dat is gedefinieerd met het kenmerk Vlaggen . Zie de sectie Opsommingstypen als bitvlagken van het artikel Opsommingstypen voor meer informatie.

Overbelasting van operatoren

Een door de gebruiker gedefinieerd type kan de ~operatoren , , <<, >>, >>>en ^ &|operators overbelasten. Wanneer een binaire operator overbelast is, wordt de bijbehorende operator voor samengestelde toewijzing ook impliciet overbelast. Een door de gebruiker gedefinieerd type kan een samengestelde toewijzingsoperator niet expliciet overbelasten.

Als een door de gebruiker gedefinieerd type T de <<, >>of >>> operator overbelast, moet het type van de linkeroperand zijn T. In C# 10 en eerder moet het type rechteroperand zijn int; vanaf C# 11 kan het type van de rechteroperand van een overbelaste ploegenoperator elk type zijn.

C#-taalspecificatie

Zie de volgende secties van de C#-taalspecificatie voor meer informatie:

Zie ook