stringtranslate.com

Operaciones bit a bit en C

En el lenguaje de programación C , las operaciones se pueden realizar a nivel de bits utilizando operadores bit a bit .

Las operaciones a nivel de bit se contrastan con las operaciones a nivel de byte , que caracterizan a las contrapartes lógicas de los operadores a nivel de bit, los operadores AND, OR y NOT. En lugar de actuar sobre bits individuales, los operadores a nivel de byte actúan sobre cadenas de ocho bits (conocidos como bytes) a la vez. La razón de esto es que un byte es normalmente la unidad más pequeña de memoria direccionable (es decir, datos con una dirección de memoria única ).

Esto también se aplica a los operadores bit a bit, lo que significa que aunque operan solo en un bit a la vez, no pueden aceptar nada más pequeño que un byte como entrada.

Todos estos operadores también están disponibles en C++ y en muchos lenguajes de la familia C.

Operadores bit a bit

C proporciona seis operadores para la manipulación de bits . [1]

El operador AND bit a bit es un solo ampersand: &. Es simplemente una representación de AND que realiza su trabajo en los bits de los operandos en lugar de en el valor verdadero de los operandos. El operador AND binario bit a bit realiza una conjunción lógica (que se muestra en la tabla anterior) de los bits en cada posición de un número en su forma binaria.

Por ejemplo, trabajando con un byte (el tipo char):

 11001000  & 10111000 -------- = 10001000

El bit más significativo del primer número es 1 y el del segundo número también es 1, por lo que el bit más significativo del resultado es 1; en el segundo bit más significativo, el bit del segundo número es cero, por lo que tenemos el resultado como 0. [2]

Operación bit a bit OR|

Similar al AND bit a bit, el OR bit a bit realiza una disyunción lógica a nivel de bit. Su resultado es un 1 si cualquiera de los bits es 1 y cero solo cuando ambos bits son 0. Su símbolo es |que puede llamarse una tubería.

 11001000  | 10111000 -------- = 11111000

[2]

XOR bit a bit^

El XOR (o exclusivo) bit a bit realiza una disyunción exclusiva , que es equivalente a sumar dos bits y descartar el acarreo. El resultado es cero solo cuando tenemos dos ceros o dos unos. [3] XOR se puede utilizar para alternar los bits entre 1 y 0. Por lo tanto, i = i ^ 1cuando se utiliza en un bucle, alterna sus valores entre 1 y 0. [4]

 11001000  ^ 10111000 -------- = 01110000

Operadores de turno

Hay dos operadores de desplazamiento bit a bit. Son

Desplazamiento a la derecha>>

El símbolo del operador de desplazamiento a la derecha es >>. Para su funcionamiento, requiere dos operandos . Desplaza cada bit de su operando izquierdo hacia la derecha. El número que sigue al operador decide la cantidad de lugares en los que se desplazan los bits (es decir, el operando derecho). Por lo tanto, al hacerlo, ch >> 3todos los bits se desplazarán a la derecha tres lugares y así sucesivamente.

Sin embargo, tenga en cuenta que un valor de operando de desplazamiento que sea un número negativo o mayor o igual que el número total de bits de este valor genera un comportamiento indefinido . Por ejemplo, al desplazar un entero sin signo de 32 bits, una cantidad de desplazamiento de 32 o más no estaría definida.

Ejemplo:

Si la variable chcontiene el patrón de bits 11100101, entonces ch >> 1producirá el resultado 01110010y ch >> 2producirá 00111001.

Aquí, los espacios en blanco se generan simultáneamente a la izquierda cuando los bits se desplazan a la derecha. Cuando se realiza en un tipo sin signo o un valor no negativo en un tipo con signo, la operación realizada es un desplazamiento lógico , que hace que los espacios en blanco se rellenen con 0s (ceros). Cuando se realiza en un valor negativo en un tipo con signo, el resultado está técnicamente definido por la implementación (depende del compilador), [5] sin embargo, la mayoría de los compiladores realizarán un desplazamiento aritmético , que hará que el espacio en blanco se rellene con el bit de signo establecido del operando izquierdo.

El desplazamiento a la derecha se puede utilizar para dividir un patrón de bits por 2 como se muestra:

i = 14 ; // Patrón de bits 00001110 j = i >> 1 ; // aquí tenemos el patrón de bits desplazado en 1, por lo que obtenemos 00000111 = 7 que es 14/2        

Uso del operador con turno a la derecha

El uso típico de un operador de desplazamiento a la derecha en C se puede ver en el siguiente código.

Ejemplo:

#include <stdio.h> void showbits ( unsigned int x ) { int i = 0 ; para ( i = ( sizeof ( int ) * 8 ) - 1 ; i >= 0 ; i -- ) { putchar ( x & ( 1u << i ) ? '1' : '0' ); } printf ( " \n " ); }                                 int main ( void ) { int j = 5225 ; printf ( "%d en binario \t\t " , j ); showbits ( j );           /* el bucle para la operación de desplazamiento a la derecha */ for ( int m = 0 ; m <= 5 ; m ++ ) { int n = j >> m ; printf ( "%d desplazamiento a la derecha %d da " , j , m ); showbits ( n ); } return 0 ; }                       

La salida del programa anterior será

5225 en binario 0000000000000000000010100011010015225 desplazamiento a la derecha 0 da 000000000000000000010100011010015225 desplazamiento a la derecha 1 da 0000000000000000000001010001101005225 desplazamiento a la derecha 2 da 0000000000000000000000101000110105225 desplazamiento a la derecha 3 da 0000000000000000000000010100011015225 desplazamiento a la derecha 4 da 0000000000000000000000001010001105225 desplazamiento a la derecha 5 da 000000000000000000000000010100011

Desplazamiento a la izquierda

El símbolo del operador de desplazamiento a la izquierda es <<. Desplaza cada bit de su operando de la izquierda hacia la izquierda la cantidad de posiciones indicadas por el operando de la derecha. Funciona de forma opuesta a la del operador de desplazamiento a la derecha. Por lo tanto, al hacer ch << 1en el ejemplo anterior ( 11100101) tenemos 11001010. Los espacios en blanco generados se rellenan con ceros como se indica anteriormente.

Sin embargo, tenga en cuenta que un valor de operando de desplazamiento que sea un número negativo o mayor o igual que el número total de bits de este valor da como resultado un comportamiento indefinido . Esto se define en la norma ISO 9899:2011 6.5.7 Operadores de desplazamiento bit a bit. Por ejemplo, al desplazar un entero sin signo de 32 bits, una cantidad de desplazamiento de 32 o más no estaría definida.

El desplazamiento a la izquierda se puede utilizar para multiplicar un número entero por potencias de 2 como en

int i = 7 ; // El decimal 7 es binario (2^2) + (2^1) + (2^0) = 0000 0111 int j = 3 ; // El decimal 3 es binario (2^1) + (2^0) = 0000 0011 k = ( i << j ); // La operación de desplazamiento a la izquierda multiplica el valor por 2 a la potencia de j en decimal // Equivale a sumar j ceros a la representación binaria de i // 56 = 7 * 2^3 // 0011 1000 = 0000 0111 << 0000 0011                

Ejemplo: un programa de suma simple

El siguiente programa agrega dos operandos usando AND, XOR y desplazamiento a la izquierda (<<).

#incluir <stdio.h> int main ( void ) { unsigned int x = 3 , y = 1 , suma , acarreo ; suma = x ^ y ; // x XOR y acarreo = x & y ; // x Y y while ( acarreo != 0 ) { acarreo = acarreo << 1 ; // desplazar a la izquierda el acarreo x = suma ; // inicializar x como suma y = acarreo ; // inicializar y como acarreo suma = x ^ y ; // se calcula la suma acarreo = x & y ; /* se calcula el acarreo, se evalúa la condición del bucle  y se repite el proceso hasta que  el acarreo sea igual a 0.  */ } printf ( "%u \n " , suma ); // el programa imprimirá 4 y devolverá 0 ; }                                                              

Operadores de asignación bit a bit

C proporciona un operador de asignación compuesto para cada operación aritmética binaria y operación bit a bit. Cada operador acepta un operando izquierdo y un operando derecho, realiza la operación binaria apropiada en ambos y almacena el resultado en el operando izquierdo. [6]

Los operadores de asignación bit a bit son los siguientes.

Equivalentes lógicos

Cuatro de los operadores bit a bit tienen operadores lógicos equivalentes. Son equivalentes en el sentido de que tienen las mismas tablas de verdad. Sin embargo, los operadores lógicos tratan cada operando como si tuviera un solo valor, ya sea verdadero o falso, en lugar de tratar cada bit de un operando como un valor independiente. Los operadores lógicos consideran que el cero es falso y que cualquier valor distinto de cero es verdadero. Otra diferencia es que los operadores lógicos realizan una evaluación de cortocircuito .

La siguiente tabla combina operadores equivalentes y muestra a y b como operandos de los operadores.

!=tiene la misma tabla de verdad que ^los operadores lógicos verdaderos, pero a diferencia de ellos, por sí mismo !=no es estrictamente hablando un operador lógico. Esto se debe a que un operador lógico debe tratar cualquier valor distinto de cero de la misma manera. Para ser utilizado como un operador lógico, !=se requiere que los operandos se normalicen primero. Un no lógico aplicado a ambos operandos no cambiará la tabla de verdad resultante, pero garantizará que todos los valores distintos de cero se conviertan al mismo valor antes de la comparación. Esto funciona porque !en un cero siempre resulta en un uno y !en cualquier valor distinto de cero siempre resulta en un cero.

Ejemplo:

/* Pruebas de operadores lógicos y bit a bit equivalentes */ #include <stdio.h> void testOperator ( char * nombre , unsigned char era , unsigned char se esperaba );        int main ( void ) { // -- Operadores bit a bit -- //     //Tablas de verdad empaquetadas en bits const unsigned char operando1 = 0x0A ; //0000 1010 const unsigned char operando2 = 0x0C ; //0000 1100 const unsigned char expectedAnd = 0x08 ; //0000 1000 const unsigned char expectedOr = 0x0E ; //0000 1110 const unsigned char expectedXor = 0x06 ; //0000 0110 const unsigned char operando3 = 0x01 ; //0000 0001 const unsigned char expectedNot = 0xFE ; //1111 1110                                                  testOperator ( "Bitwise AND" , operando1 y operando2 , esperadoY ); testOperator ( "O bit a bit" , operando1 | operando2 , esperadoO ); testOperator ( "Bitwise XOR" , operando1 ^ operando2 , esperadoXor ); testOperator ( "NO bit a bit" , ~ operando3 , no esperado ); printf ( " \n " );                   // -- Operadores lógicos -- // const unsigned char F = 0x00 ; //Cero const unsigned char T = 0x01 ; //Cualquier valor distinto de cero              // Tablas de verdad empaquetadas en matrices const unsigned char operandArray1 [ 4 ] = { T , F , T , F }; const unsigned char operandArray2 [ 4 ] = { T , T , F , F }; const unsigned char expectedArrayAnd [ 4 ] = { T , F , F , F }; const unsigned char expectedArrayOr [ 4 ] = { T , T , T , F }; const unsigned char expectedArrayXor [ 4 ] = { F , T , T , F }; const unsigned char operandArray3 [ 2 ] = { F , T }; const unsigned char expectedArrayNot [ 2 ] = { T , F };                                                           int i ; para ( i = 0 ; i < 4 ; i ++ ) { operador_prueba ( "AND lógico" , matriz_operando1 [ i ] && matriz_operando2 [ i ], matriz_esperada_Y [ i ]); } printf ( " \n " );                  para ( i = 0 ; i < 4 ; i ++ ) { operador_prueba ( "OR lógico" , matriz_operando1 [ i ] || matriz_operando2 [ i ], matriz_operando esperada [ i ]); } printf ( " \n " );                for ( i = 0 ; i < 4 ; i ++ ) { //Necesita ! en los operandos en caso de que los valores distintos de cero sean diferentes testOperator ( "XOR lógico" , ! operandArray1 [ i ] != ! operandArray2 [ i ], expectedArrayXor [ i ]); } printf ( " \n " );                 para ( i = 0 ; i < 2 ; i ++ ) { testOperator ( "NO lógico" , ! operandArray3 [ i ], expectedArrayNot [ i ]); } printf ( " \n " );              devuelve 0 ; } void testOperator ( char * nombre , unsigned char era , unsigned char esperado ) { char * resultado = ( era == esperado ) ? "pasó" : "falló" ; printf ( "%s %s, era: %X esperado: %X \n " , nombre , resultado , era , esperado ); }                          

La salida del programa anterior será

Se aprobó el AND bit a bit, era: 8, se esperaba: 8 Se pasó OR bit a bit, se esperaba: E Se aprobó la operación XOR bit a bit, se esperaba: 6, se esperaba: 6 Bitwise NO se pasó, era: FE Se esperaba: FE  AND lógico superado, era: 1 esperado: 1 AND lógico superado, era: 0 esperado: 0 AND lógico superado, era: 0 esperado: 0 AND lógico superado, era: 0 esperado: 0  Se aprobó el OR lógico, se esperaba: 1: 1 Se aprobó el OR lógico, se esperaba: 1: 1 Se aprobó el OR lógico, se esperaba: 1: 1 Se aprobó el OR lógico, se esperaba: 0, se esperaba: 0  XOR lógico superado, era: 0 esperado: 0 XOR lógico superado, era: 1 esperado: 1 XOR lógico superado, era: 1 esperado: 1 XOR lógico superado, era: 0 esperado: 0  NO lógico aprobado, era: 1 esperado: 1 NO lógico pasado, era: 0 esperado: 0

Véase también

Referencias

  1. ^ Kernighan ; Dennis M. Ritchie (marzo de 1988). El lenguaje de programación C (2.ª ed.). Englewood Cliffs, NJ : Prentice Hall . ISBN 0-13-110362-8Archivado desde el original el 6 de julio de 2019. Consultado el 7 de septiembre de 2019 .Considerado por muchos como la referencia autorizada sobre C.
  2. ^ ab "Tutoriales - Operadores bit a bit y manipulaciones de bits en C y C++". cprogramming.com .
  3. ^ "Tutorial de compuerta OR exclusiva". Tutoriales básicos de electrónica .
  4. ^ "Notas de C++: Operadores bit a bit". fredosaurus.com .
  5. ^ "ISO/IEC 9899:2011 - Tecnología de la información -- Lenguajes de programación -- C". www.iso.org .
  6. ^ "Operadores de asignación compuestos". IBM . International Business Machines . Consultado el 29 de enero de 2022 .

Enlaces externos