Comparteix via


Operadores de desplazamiento y bit a bit (referencia de C#)

Los operadores bit a bit y de desplazamiento incluyen complementos unarios bit a bit, desplazamiento binario a izquierda y derecha, desplazamiento a la derecha sin signo y los operadores OR lógicos binarios AND, OR y OR exclusivos. Estos operadores toman operandos de los tipos numéricos enteros o del tipo char .

Puede usar estos operadores con los inttipos , uint, longulong, , ninty nuint . Cuando ambos operandos son de otro tipo entero (sbyte, byte, short, ushort o char), sus valores se convierten en el tipo int, que también es el tipo de resultado de una operación. Cuando los operandos son de tipo entero diferente, sus valores se convierten en el tipo entero más cercano que contenga. Para obtener más información, vea la sección Promociones numéricas de Especificación del lenguaje C#. Los operadores compuestos (como >>=) no convierten sus argumentos en int o tienen el tipo de resultado como int.

Los &operadores , |y ^ también funcionan con operandos del bool tipo . Para obtener más información, vea Operadores lógicos booleanos.

Las operaciones de desplazamiento y bit a bit nunca producen desbordamiento y generan los mismos resultados en contextos Checked y Unchecked.

La documentación de referencia del lenguaje C# cubre la versión más reciente publicada del lenguaje C#. También contiene documentación inicial sobre las características de las versiones preliminares públicas de la próxima versión del lenguaje.

La documentación identifica cualquier característica introducida por primera vez en las últimas tres versiones del idioma o en las versiones preliminares públicas actuales.

Sugerencia

Para buscar cuándo se introdujo por primera vez una característica en C#, consulte el artículo sobre el historial de versiones del lenguaje C#.

Operador de complemento bit a bit ~

El operador ~ genera un complemento bit a bit de su operando al invertir 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

También se puede usar el símbolo ~ para declarar finalizadores. Para obtener más información, vea Finalizadores.

Operador de desplazamiento izquierdo <<

El << operador desplaza su operando izquierdo a la izquierda por el número de bits especificados por su operando derecho. Para obtener más información sobre cómo el operando derecho define el recuento de desplazamientos, consulte la sección Recuento de desplazamientos de la sección Operadores de desplazamiento .

La operación de desplazamiento a la izquierda descarta los bits de orden superior que se encuentran fuera del intervalo del tipo de resultado. Establece las posiciones de bits vacías de orden bajo en cero, como se muestra en el ejemplo siguiente:

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

Dado que los operadores de desplazamiento solo se definen para los tipos int, uint, long y ulong, el resultado de una operación siempre contiene al menos 32 bits. Si el operando izquierdo usa otro tipo entero (sbyte, byte, short, ushorto char), la operación convierte su valor en el tipo, como se muestra en el int ejemplo siguiente:

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 desplazamiento a la derecha >>

El operador >> desplaza el operando izquierdo a la derecha el número de bits definido por el operando derecho. Para obtener información sobre cómo el operando derecho define el recuento de desplazamiento, vea la sección Recuento de desplazamiento de los operadores de desplazamiento.

La operación de desplazamiento derecho descarta los bits de orden inferior, como se muestra en el ejemplo siguiente:

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

Las posiciones de bits vacíos de orden superior se establecen basándose en el tipo del operando izquierdo, tal como se indica a continuación:

  • Si el operando izquierdo es de tipo int o long, el operador de desplazamiento a la derecha realiza un desplazamiento aritmético: el valor del bit más significativo (el bit de signo) del operando izquierdo se propaga a las posiciones de bits vacíos de orden superior. Es decir, las posiciones de bits vacíos de orden superior se establecen en cero si el operando izquierdo no es negativo y, en caso de serlo, se establecen en uno.

    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 el operando izquierdo es de tipo uint o ulong, el operador de desplazamiento a la derecha realiza un desplazamiento lógico: las posiciones de bits vacíos de orden superior se establecen siempre en cero.

    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
    

Nota

Use el operador de desplazamiento a la derecha sin signo para realizar un desplazamiento lógico en operandos de tipos enteros con signo. Se prefiere el desplazamiento lógico. Evite convertir el operando izquierdo en un tipo sin signo y, a continuación, vuelva a convertir el resultado de una operación de desplazamiento a un tipo con signo.

Operador de desplazamiento a la derecha sin signo >>>

El operador >>> desplaza el operando izquierdo a la derecha el número de bits definido por el operando derecho. Para obtener información sobre cómo el operando derecho define el recuento de desplazamiento, vea la sección Recuento de desplazamiento de los operadores de desplazamiento.

El >>> operador siempre realiza un desplazamiento lógico. Es decir, las posiciones de bits vacías de orden alto siempre se establecen en cero, independientemente del tipo del operando izquierdo. El >> operador realiza un desplazamiento aritmético (es decir, el valor del bit más significativo se propaga a las posiciones de bits vacías de orden alto) si el operando izquierdo es de un tipo con signo. En el ejemplo siguiente se muestra la diferencia entre los operadores de >> y >>> para un operando izquierdo 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 &

El operador & calcula el AND lógico bit a bit de sus operandos enteros:

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

Para los operandos bool, el operador & calcula el AND lógico de sus operandos. El operador & unario es el operador address-of.

Operador IR exclusivo lógico ^

El operador ^ calcula el OR exclusivo lógico bit a bit, también conocido como XOR lógico bit a bit, de sus operandos enteros:

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

Para los operandos bool, el operador ^ calcula el OR exclusivo lógico de sus operandos.

Operador lógico OR |

El operador | calcula el OR lógico bit a bit de sus operandos enteros:

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

Para los operandos bool, el operador | calcula el OR lógico de sus operandos.

Asignación compuesta

Para un operador binario op, una expresión de asignación compuesta con el formato

x op= y

Es equivalente a

x = x op y

Excepto que x solo se evalúe una vez.

En el ejemplo siguiente se muestra el uso de la asignación compuesta con operadores de desplazamiento y bit a 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}");

Debido a las promociones numéricas, es posible que el resultado de la op operación no se pueda convertir implícitamente en el tipo T de x. En tal caso, si op es un operador predefinido y el resultado de la operación se convierte explícitamente en el tipo T de x, una expresión de asignación compuesta del formulario x op= y es equivalente a x = (T)(x op y), excepto que el x objeto se evalúa solo una vez. En el ejemplo siguiente se muestra ese comportamiento:

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

Prioridad de operadores

La siguiente lista ordena los operadores bit a bit y desplazan de la prioridad más alta a la prioridad más baja:

  • Operador de complemento bit a bit ~
  • Operadores de desplazamiento <<, >>y >>>
  • Operador AND lógico &
  • Operador OR exclusivo lógico ^
  • Operador OR lógico |

Use paréntesis, (), para cambiar el orden de evaluación de la precedencia del operador predeterminado:

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 obtener la lista completa de los operadores de C# ordenados por nivel de prioridad, vea la sección Prioridad de operadores del artículo Operadores de C#.

Recuento de desplazamiento de los operadores de desplazamiento

Para las expresiones de x << count, x >> county x >>> count , el recuento de desplazamientos real depende del tipo de xde la siguiente manera:

  • Si el tipo de x es int o uint, el recuento de desplazamiento viene definido por los cinco bits de orden inferior del operando derecho. Es decir, el valor de desplazamiento se calcula a partir de count & 0x1F (o count & 0b_1_1111).

  • Si el tipo de x es long o ulong, los seis bits de orden inferior del operando derecho definen el recuento de turnos. Es decir, el valor de desplazamiento se calcula a partir de count & 0x3F (o count & 0b_11_1111).

En el ejemplo siguiente se muestra ese comportamiento:

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

Nota

Tal y como se muestra en el ejemplo anterior, el resultado de una operación de desplazamiento puede ser distinto de cero incluso si el valor del operando derecho es mayor que el número de bits del operando izquierdo.

Operadores lógicos de enumeración

Cada tipo de enumeración admite los ~operadores , &, |y ^ . En el caso de los operandos del mismo tipo de enumeración, se realiza una operación lógica en los valores correspondientes del tipo entero subyacente. Por ejemplo, para cualquier x e y de un tipo de enumeración T con un tipo subyacente U, la expresión x & y produce el mismo resultado que la expresión (T)((U)x & (U)y).

Normalmente, los operadores lógicos bit a bit se usan con un tipo de enumeración definido con el atributo Flags. Para obtener más información, vea la sección Tipos de enumeración como marcas de bits del artículo Tipos de enumeración.

Posibilidad de sobrecarga del operador

Un tipo definido por el usuario puede sobrecargar los operadores ~, <<, >>, >>>, &, |y ^ . Al sobrecargar un operador binario, también sobrecarga implícitamente el operador de asignación compuesta correspondiente. A partir de C# 14, un tipo definido por el usuario puede sobrecargar explícitamente los operadores de asignación compuesta para proporcionar una implementación más eficaz. Normalmente, un tipo sobrecarga estos operadores porque el valor se puede actualizar en su lugar, en lugar de asignar una nueva instancia para almacenar el resultado de la operación binaria. Si un tipo no proporciona una sobrecarga explícita, el compilador genera la sobrecarga implícita.

Si un tipo definido por el usuario T sobrecarga el operador <<, >>o >>> , el tipo del operando izquierdo debe ser T. En C# 10 y versiones anteriores, el tipo del operando derecho debe ser int; el tipo del operando derecho de un operador de desplazamiento sobrecargado puede ser cualquiera.

especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Consulte también