Bitové operátory a operátory shift (referenční dokumentace jazyka C#)

Bitové operátory a operátory posunu zahrnují unární bitový doplněk, binární levý a pravý posun, posun doprava bez znaménka a binární logické operátory AND, OR a exkluzivní operátory OR. Tyto operandy přebírají operandy celočíselných číselných typů nebo typu znaku.

Tyto operátory jsou definovány pro int, uint, longa ulong typy. Jsou-li oba operandy jiné celočíselné typy (sbyte, byte, short, ushortnebo char), jejich hodnoty jsou převedeny na int typ, což je také typ výsledku operace. Pokud jsou operandy různých integrálních typů, jejich hodnoty se převedou na nejbližší celočíselný typ. Další informace najdete v části Číselné povýšení specifikace jazyka C#. Složené operátory (například >>=) nepřevádějí jejich argumenty nebo int mají typ výsledku jako int.

Operátory &, |a ^ jsou také definovány pro operandy bool typu. Další informace najdete v tématu Logické logické operátory.

Bitové operace a operace posunu nikdy nezpůsobí přetečení a vytvoří stejné výsledky v nezaškrtnutých kontextech.

Bitový doplněk – operátor ~

Operátor ~ vytvoří bitový doplněk svého operandu vrácením každého bitu:

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

Pomocí symbolu ~ můžete deklarovat finalizační metody. Další informace naleznete v tématu Finalizers.

Operátor levého posunu <<

Operátor << posune svůj operand vlevo o počet bitů definovaných jeho operandem na pravé straně. Informace o tom, jak pravý operand definuje počet směn, najdete v části Operátory směny .

Operace levého posunu zahodí bity s vysokým pořadím, které jsou mimo rozsah typu výsledku, a nastaví pozice prázdných bitů s nízkým pořadím na nulu, jak ukazuje následující příklad:

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

Protože operátory posunu jsou definovány pouze pro int, longuinta ulong typy, výsledek operace vždy obsahuje alespoň 32 bitů. Pokud je levý operand jiného celočíselného typu (sbyte, byte, short, ushortnebo char), jeho hodnota je převedena na int typ, jak ukazuje následující příklad:

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

Operátor posunu doprava >>

Operátor >> posune operand zleva doprava o počet bitů definovaných jeho operandem zprava. Informace o tom, jak pravý operand definuje počet směn, najdete v části Operátory směny .

Operace posunu vpravo zahodí bity s nízkým pořadím, jak ukazuje následující příklad:

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

Pozice prázdných bitů s vysokým pořadím jsou nastaveny na základě typu levého operandu následujícím způsobem:

  • Pokud je operand na levé straně typu int nebo long, operátor posunu vpravo provede aritmetický posun: hodnota nejvýznamnějšího bitu (bitu znaménka) levého operandu se rozšíří na pozice prázdných bitů s vysokým pořadím. To znamená, že pozice prázdných bitů s vysokým pořadím jsou nastaveny na nulu, pokud je levý operand nezáporný a nastaví se na jednu, pokud je záporná.

    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
    
  • Pokud je operand vlevo typu uint nebo ulong, operátor posunu vpravo provede logický posun: pozice prázdných bitů ve vysokém pořadí jsou vždy nastaveny na nulu.

    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
    

Poznámka:

Pomocí operátoru posunu doprava bez znaménka můžete provést logický posun u operandů s typy celých čísel se znaménkem. Toto je upřednostňované pro přetypování levého operandu na nepodepsaný typ a následné přetypování výsledku operace posunu zpět na podepsaný typ.

Operátor posunu doprava bez znaménka >>>

K dispozici v jazyce C# 11 a novějším >>> operátor posune svůj operand vlevo o počet bitů definovaných jeho operandem vpravo. Informace o tom, jak pravý operand definuje počet směn, najdete v části Operátory směny .

Operátor >>> vždy provádí logický posun. To znamená, že pozice prázdných bitů s vysokým pořadím jsou vždy nastaveny na nulu bez ohledu na typ levého operandu. Operátor >> provede aritmetický posun (tj. hodnota nejvýznamnějšího bitu se rozšíří na pozice prázdných bitů s vysokým pořadím), pokud je levý operand typu signed. Následující příklad ukazuje rozdíl mezi >> operandem a >>> operátory pro záporný levý operand:

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

Logický operátor AND &

Operátor & vypočítá bitový logický operátor AND jeho integrálních operandů:

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

Operátor pro bool operandy & vypočítá logický operátor AND jeho operandů. Unární & operátor je operátor address-of.

Logický exkluzivní operátor OR ^

Operátor ^ vypočítá bitový logický exkluzivní operátor OR, označovaný také jako bitový logický XOR, jeho integrálních operandů:

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

Operátor pro bool operandy ^ vypočítá logický exkluzivní operátor OR svých operandů.

Logický operátor OR |

Operátor | vypočítá bitový logický operátor OR integrálních operandů:

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

Operátor pro bool operandy | vypočítá logickou hodnotu OR svých operandů.

Složené přiřazení

U binárního operátoru opje složený výraz přiřazení formuláře.

x op= y

je ekvivalentem

x = x op y

s tím rozdílem, že x se vyhodnotí pouze jednou.

Následující příklad ukazuje použití složeného přiřazení s bitovými operátory a operátory shift:

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

Z důvodu číselných povýšení nemusí být výsledek op operace implicitně konvertibilní na typ Tx. V takovém případě je-li op předdefinovaný operátor a výsledek operace je explicitně konvertibilní na typ xT , složený výraz přiřazení formuláře x op= y je ekvivalentní x = (T)(x op y), s výjimkou toho, že x je vyhodnocen pouze jednou. Následující příklad ukazuje toto chování:

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

Priorita operátorů

Následující seznam obsahuje bitové operátory a operátory posunu počínaje nejvyšší prioritou až po nejnižší:

  • Bitový operátor doplňku ~
  • Operátory <<shift , >>a >>>
  • Logický operátor AND &
  • Logický exkluzivní operátor OR ^
  • Logický operátor OR |

Pomocí závorek změňte ()pořadí vyhodnocení uložené podle priority operátoru:

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

Úplný seznam operátorů jazyka C# seřazených podle úrovně priority najdete v části Priorita operátorů v článku operátory jazyka C#.

Počet směn operátorů směn

Pro předdefinované operátory <<posunu , >>a >>>, typ pravého operandu musí být int nebo typ, který má předdefinovaný implicitní číselný převod na int.

x << countPro výrazy , x >> counta x >>> count výrazy skutečný počet směn závisí na typu x následujícím způsobem:

  • Pokud je typ nebo , je počet směn definován pěti bity pravého operandu s nízkým pořadím.uintxint To znamená, že se počítá počet směn ( count & 0x1F nebo count & 0b_1_1111).

  • Pokud je long typ x nebo ulong, je počet směn definován šesti bity pravého operandu. To znamená, že se počítá počet směn ( count & 0x3F nebo count & 0b_11_1111).

Následující příklad ukazuje toto chování:

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

Poznámka:

Jak ukazuje předchozí příklad, výsledek operace posunu může být nenulový, i když je hodnota pravého operandu větší než počet bitů v levém operandu.

Logické operátory výčtu

Operátory , , a ^ jsou podporovány také všemi typy výčtu. |&~ Pro operandy stejného typu výčtu se logická operace provádí s odpovídajícími hodnotami základního integrálního typu. Například pro libovolný x typ výčtu Ty s podkladovým typem Ux & y výraz vytvoří stejný výsledek jako (T)((U)x & (U)y) výraz.

Obvykle používáte bitové logické operátory s typem výčtu, který je definován pomocí atributu Flags . Další informace naleznete v části Typy výčtu jako příznaky bitův článku Výčtové typy .

Přetížení operátoru

Uživatelem definovaný typ může přetížit ~ operátory , , >>>>><<, &, |a ^ operátory. Pokud je binární operátor přetížen, odpovídající operátor složeného přiřazení je také implicitně přetížen. Uživatelem definovaný typ nemůže explicitně přetížit operátor složeného přiřazení.

Pokud uživatelem definovaný typ T přetěžuje <<, >>nebo >>> operátor, typ levého operandu musí být T. V jazyce C# 10 a starším musí být inttyp pravého operandu . Počínaje jazykem C# 11 může být typ operandu přetížené směny libovolný typ operandu pravé ruky.

specifikace jazyka C#

Další informace najdete v následujících částech specifikace jazyka C#:

Viz také