Compartilhar via


Operadores bit a bit e de deslocamento (referência do C#)

Os operadores bit a bit e de deslocamento incluem complemento bit a bit unário, deslocamento binário para a esquerda e a direita, deslocamento sem sinal para a direita e os operadores binários lógicos AND, OR e OR exclusivo. Esses operadores assumem operandos dos tipos numéricos integrais ou do tipo char .

Você pode usar esses operadores com os inttipos , , uintlong, ulonge nintnuint . Quando ambos os operandos são de outros tipos integrais (sbyte, byte, short, ushort ou char), seus valores são convertidos no tipo int, que também é o tipo de resultado de uma operação. Quando os operandos são de tipos integrais diferentes, seus valores são convertidos no tipo integral mais próximo que o contém. Para saber mais, confira a seção Promoções numéricas da Especificação da linguagem C#. Os operadores compostos (como >>=) não convertem seus argumentos em int ou têm o tipo de resultado como int.

Os &operadores e | os ^operadores também funcionam com operandos do bool tipo. Para obter mais informações, veja Operadores lógicos boolianos.

As operações de deslocamento e bit a bit nunca causam estouro e produzem os mesmos resultados nos contextos marcados e desmarcados.

A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento do idioma.

A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.

Dica

Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.

Operador de complemento bit a bit ~

O operador ~ produz um complemento bit a bit de seu operando invertendo cada bit:

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

Você também pode usar o símbolo ~ para declarar finalizadores. Para mais informações, consulte Finalizadores.

Operador de deslocamento à esquerda <<

O << operador desloca seu operando à esquerda para a esquerda pelo número de bits especificado por seu operando à direita. Para obter mais informações sobre como o operando à direita define a contagem de turnos, consulte a contagem shift da seção de operadores de deslocamento .

A operação de deslocamento esquerdo descarta os bits de alta ordem que ficam fora do intervalo do tipo de resultado. Ele define as posições de bit vazias de ordem baixa como zero, como mostra o exemplo a seguir:

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

Como os operadores de deslocamento são definidos apenas para os tipos int, uint, long e ulong, o resultado de uma operação sempre contém pelo menos 32 bits. Se o operando à esquerda usar outro tipo integral (sbyte, , byte, shortou ushortchar), a operação converterá seu valor no int tipo, como mostra o exemplo a seguir:

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

Operador de deslocamento à direita >>

O operador >> desloca para direita o operando à esquerda pelo número de bits definido pelo seu operando à direita. Para saber mais sobre como o operando à direita define a contagem de deslocamento, veja a seção Contagem de deslocamento dos operadores de deslocamento.

A operação de deslocamento à direita descarta os bits de ordem inferior, como mostra o exemplo a seguir:

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

As posições vazias de bit de ordem superior são definidas com base no tipo do operando à esquerda da seguinte maneira:

  • Se o operando à esquerda for do tipo int ou long, o operador de deslocamento à direita executará um deslocamento aritmético: o valor do bit mais significativo (o bit de sinal) do operando à esquerda é propagado para as posições vazias de bits de ordem superior. Ou seja, as posições vazias de bit de ordem superior são definidas como zero se o operando à esquerda for positivo e definidas como um se ele for negativo.

    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
    
  • Se o operando à esquerda for do tipo uint ou ulong, o operador de deslocamento à direita executará um deslocamento lógico: as posições vazias de bit de ordem superior são sempre definidas como zero.

    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
    

Observação

Use o operador de deslocamento à direita sem sinal para executar um deslocamento lógica em operandos de tipos inteiros com sinal. A mudança lógica é preferencial. Evite converter o operando esquerdo em um tipo sem sinal e, em seguida, converter o resultado de uma operação de deslocamento de volta para um tipo assinado.

Operador de deslocamento para a direita sem sinal >>>

O operador >>> desloca para direita o operando à esquerda pelo número de bits definido pelo seu operando à direita. Para saber mais sobre como o operando à direita define a contagem de deslocamento, veja a seção Contagem de deslocamento dos operadores de deslocamento.

O operador >>> sempre realiza um deslocamento lógico. Ou seja, as posições de bits vazias de alta ordem são sempre definidas como zero, independentemente do tipo do operando à esquerda. O operador >> executa um deslocamento aritmético (ou seja, o valor do bit mais significativo é propagado para as posições de bit vazias de alta ordem) se o operando à esquerda for de um tipo assinado. O seguinte exemplo demonstra a diferença entre os operadores >> e >>> para um operando à esquerda negativo:

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

Operador AND lógico &

O operador & computa o AND lógico bit a bit de seus operandos integrais:

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

Para operandos bool, o operador & computa o AND lógico de seus operandos. O operador & unário é o operador address-of.

Operador OR exclusivo lógico ^

O operador ^ computa o OR exclusivo lógico bit a bit, também conhecido como o XOR lógico bit a bit, de seus operandos integrais:

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

Para operandos bool, o operador ^ computa o OR exclusivo lógico de seus operandos.

Operador OR lógico |

O operador | computa o OR lógico bit a bit de seus operandos integrais:

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

Para operandos bool, o operador | computa o OR lógico de seus operandos.

Atribuição composta

Para um operador binário op, uma expressão de atribuição composta do formato

x op= y

É equivalente a

x = x op y

Exceto que x é avaliado apenas uma vez.

O seguinte exemplo demonstra o uso da atribuição composta com operadores bit a bit e de deslocamento:

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

Devido a promoções numéricas, o resultado da op operação pode não ser implicitamente conversível para o tipo T de x. Nesse caso, se op for um operador predefinido e o resultado da operação for explicitamente conversível para o tipo T de, uma expressão de xatribuição composta do formulário x op= y será equivalente a x = (T)(x op y), exceto que o x é avaliado apenas uma vez. O exemplo a seguir demonstra esse comportamento:

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

Precedência do operador

A lista a seguir ordena operadores bit a bit e shift em grupos da precedência mais alta para a precedência mais baixa:

Use parênteses, ()para alterar a ordem de avaliação da precedência do operador padrão:

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

Para obter a lista completa de operadores C# ordenados por nível de precedência, consulte a seção Precedência de operador do artigo Operadores C#.

Contagem de deslocamento dos operadores de deslocamento

Para as expressões x << count, x >> count e x >>> count, a contagem real de deslocamento depende do tipo de x da seguinte maneira:

  • Se o tipo de x for int ou uint, os cinco bits de ordem inferior do operando à direita definirão a contagem de deslocamento. Ou seja, a contagem de deslocamentos é calculada a partir de count & 0x1F (ou count & 0b_1_1111).

  • Se o tipo de x for long ou ulong, os seis bits de ordem inferior do operando à direita definirão a contagem de deslocamento. Ou seja, a contagem de deslocamentos é calculada a partir de count & 0x3F (ou count & 0b_11_1111).

O exemplo a seguir demonstra esse comportamento:

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

Observação

Como mostra o exemplo anterior, o resultado de uma operação de deslocamento pode ser diferente de zero mesmo que o valor do operando à direita seja maior do que o número de bits no operando à esquerda.

Operadores lógicos de enumeração

Cada tipo de enumeração dá suporte aos operadores ~, &, | e ^. Para operandos do mesmo tipo de enumeração, uma operação lógica é executada nos valores correspondentes do tipo integral subjacente. Por exemplo, para qualquer x e y de um tipo de enumeração T com um tipo subjacente U, a expressão x & y produz o mesmo resultado que a expressão (T)((U)x & (U)y).

Geralmente, você usa os operadores lógicos bit a bit com um tipo de enumeração definido com o atributo sinalizadores. Para obter mais informações, veja a seção Tipos de enumeração como sinalizadores de bit do artigo Tipos de enumeração.

Capacidade de sobrecarga do operador

Um tipo definido pelo usuário pode sobrecarregar os operadores ~, <<, >>, >>>, &, |e ^. Ao sobrecarregar um operador binário, você também sobrecarrega implicitamente o operador de atribuição composta correspondente. A partir do C# 14, um tipo definido pelo usuário pode sobrecarregar explicitamente os operadores de atribuição composta para fornecer uma implementação mais eficiente. Normalmente, um tipo sobrecarrega esses operadores porque o valor pode ser atualizado no local, em vez de alocar uma nova instância para armazenar o resultado da operação binária. Se um tipo não fornecer uma sobrecarga explícita, o compilador gerará a sobrecarga implícita.

Se um tipo definido pelo usuário T sobrecarregar o operador <<, >> ou >>>, o tipo do operando à esquerda deverá ser T. No C# 10 e anterior, o tipo do operando à direita deve ser int; o tipo do operando à direita de um operador de deslocamento sobrecarregado pode ser qualquer.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Confira também