Miércoles, 23 de Junio de 2010
admin
Hace unos días empecé con la serie Bailando con Bits (aunque llevaba escrito varios meses) trata de formas para trabajar a nivel de bit desde C.
Hoy voy a proponer otra forma, quizás menos intuitiva que la anterior, pero diferente. Esta vez no utilizaremos un registro enorme ni nada parecido, utilizaremos un mismo número entero para hacer el ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include <stdio.h>
#define PESOBIT(bpos) 1<<bpos
#define COGEBIT(var,bpos) (var & PESOBIT(bpos))?1:0
#define PONE_1(var,bpos) var | PESOBIT(bpos)
#define PONE_0(var,bpos) var & ~(PESOBIT(bpos))
#define CAMBIA(var,bpos) var ^ PESOBIT(bpos)
int main ()
{
int numero ;
int i ;
numero =63;
printf ("Numero: %d\n", numero );
for (i =31; i >=0; i --)
printf("%4d", i );
printf("\n");
for (i =31; i >=0; i --)
printf("%4d",COGEBIT (numero ,i ));
printf("\n");
numero =PONE_1 (numero , 17);
numero =PONE_0 (numero , 3);
numero =CAMBIA (numero , 20);
numero =CAMBIA (numero , 5);
for (i =31; i >=0; i --)
printf("%4d",COGEBIT (numero ,i ));
printf("\nNúmero: %d\n", numero );
} |
Ahora usamos varias macros que harán operaciones de bit con la variable a analizar (están definidas en la parte de arriba), tenemos PESOBIT, COGEBIT, PONE_1, PONE_0 y CAMBIA:
- PESOBIT: Nos dice cuánto vale un bit con valor 1 en la posición especificada, por ejemplo en la posición 0 (LSB) vale 1, en la posición 1, vale 2, en la posición 3, vale 4, en la posición 4, vale 8…
- COGEBIT: Nos dice si el bit en la posición bpos de la variable var vale 0 ó 1
- PONE_1: Pone un 1 en el bit bpos de la variable var
- PONE_0: Pone un 0 en el bit bpos de la variable var
- CAMBIA: Cambia el valor (de 0 a 1 y viceversa) del bit en la posición bpos de la variable var
Como vemos en el ejemplo si queremos poner a 1 el bit 5 de numero, tendremos que hacer numero=PONE_1(numero,5), aunque en el siguiente ejemplo veremos cómo simplificar todo eso.
Con este ejemplo podemos jugar con los bits de números enteros. Pero, y si queremos utilizar otro tipo de variables? (aunque estamos limitados a 32bits) También tenemos este ejemplo con un tipo float:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include <stdio.h>
#define PESOBIT(bpos) 1<<bpos
#define COGEBIT(var,bpos) (*(unsigned*)&var & PESOBIT(bpos))?1:0
#define PONE_1(var,bpos) *(unsigned*)&var |= PESOBIT(bpos)
#define PONE_0(var,bpos) *(unsigned*)&var &= ~(PESOBIT(bpos))
#define CAMBIA(var,bpos) *(unsigned*)&var ^= PESOBIT(bpos)
int main ()
{
float numero ;
int i ;
numero =63.2317;
printf ("Numero: %f\n", numero );
for (i =31; i >=0; i --)
printf("%4d", i );
printf("\n");
for (i =31; i >=0; i --)
printf("%4d",COGEBIT (numero ,i ));
printf("\n");
PONE_1 (numero , 5);
PONE_0 (numero , 3);
CAMBIA (numero , 20);
CAMBIA (numero , 5);
CAMBIA (numero , 31);
for (i =31; i >=0; i --)
printf("%4d",COGEBIT (numero ,i ));
printf("\n");
printf("\nNúmero: %f\n", numero );
} |
En este caso no tenemos que hacer una variable igual a PONE_1(variable, 5) para poner su bit a 1; simplemente con PONE_1(variable, 5) nos vale. En este ejemplo podemos ver una variable de tipo float desglosada en bits y podemos modificar a nivel de bit para obtener otros valores. (No le veo mucha utilidad a esto, pero bueno).
Post dedicado a algm, por su comentario en el artículo Bailando con bits anterior.
Categories: C/C++ Tags: and, bailar, bits, byte, float, inspeccionar, int, investigar, logica, or, recorrer, resta, suma, variable, xor
Jueves, 10 de Junio de 2010
admin
Hay muchas formas para hacer esto, pero quizás la más visual (tal vez también útil algunas veces) es la siguiente (se explica más abajo):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include <stdio.h>
typedef struct {
unsigned int b1 :1;
unsigned int b2 :1;
unsigned int b3 :1;
unsigned int b4 :1;
unsigned int b5 :1;
unsigned int b6 :1;
unsigned int b7 :1;
unsigned int b8 :1;
unsigned int b9 :1;
unsigned int b10 :1;
unsigned int b11 :1;
unsigned int b12 :1;
unsigned int b13 :1;
unsigned int b14 :1;
unsigned int b15 :1;
unsigned int b16 :1;
unsigned int b17 :1;
unsigned int b18 :1;
unsigned int b19 :1;
unsigned int b20 :1;
unsigned int b21 :1;
unsigned int b22 :1;
unsigned int b23 :1;
unsigned int b24 :1;
unsigned int b25 :1;
unsigned int b26 :1;
unsigned int b27 :1;
unsigned int b28 :1;
unsigned int b29 :1;
unsigned int b30 :1;
unsigned int b31 :1;
unsigned int b32 :1;
} Tint_bits ;
int main ()
{
int numero ;
Tint_bits *bitpack ;
bitpack =(Tint_bits *)&numero ;
numero =63;
printf ("Dir cos: %X\nDir paq: %X\n", &numero , bitpack ); // Vemos que las direcciones de memoria son idénticas.
printf ("Numero: %d\n", numero );
printf ("Bit 1: %d\n", bitpack ->b1 );
printf ("Bit 2: %d\n", bitpack ->b2 );
printf ("Bit 3: %d\n", bitpack ->b3 );
printf ("Bit 4: %d\n", bitpack ->b4 );
printf ("Bit 5: %d\n", bitpack ->b5 );
printf ("Bit 6: %d\n", bitpack ->b6 );
printf ("Bit 7: %d\n", bitpack ->b7 );
printf ("Bit 8: %d\n", bitpack ->b8 );
printf ("Bit 9: %d\n", bitpack ->b9 );
printf ("Bit10: %d\n", bitpack ->b10 );
printf ("Bit11: %d\n", bitpack ->b11 );
printf ("Bit12: %d\n", bitpack ->b12 );
printf ("Bit13: %d\n", bitpack ->b13 );
printf ("Bit14: %d\n", bitpack ->b14 );
printf ("Bit15: %d\n", bitpack ->b15 );
printf ("Bit16: %d\n", bitpack ->b16 );
printf ("Bit17: %d\n", bitpack ->b17 );
printf ("Bit18: %d\n", bitpack ->b18 );
printf ("Bit19: %d\n", bitpack ->b19 );
printf ("Bit20: %d\n", bitpack ->b20 );
printf ("Bit21: %d\n", bitpack ->b21 );
printf ("Bit22: %d\n", bitpack ->b22 );
printf ("Bit23: %d\n", bitpack ->b23 );
printf ("Bit24: %d\n", bitpack ->b24 );
printf ("Bit25: %d\n", bitpack ->b25 );
printf ("Bit26: %d\n", bitpack ->b26 );
printf ("Bit27: %d\n", bitpack ->b27 );
printf ("Bit28: %d\n", bitpack ->b28 );
printf ("Bit29: %d\n", bitpack ->b29 );
printf ("Bit30: %d\n", bitpack ->b30 );
printf ("Bit31: %d\n", bitpack ->b31 );
printf ("Bit32: %d\n", bitpack ->b32 );
bitpack ->b9 =1;
printf("Numero= %d\n", numero );
} |
Primero creamos un espacio de bits en nuestro registro Tint_bits, con ello, hacemos 32 variables de tamaño 1 bit (con un espacio en memoria de 32bits (lo que es un entero de 32bits). Lo que hacemos para poder consultar los bits, es crear un puntero de este tipo (Tint_bits) que apunte a la dirección de memoria de nuestro número, con ello podremos leer en memoria, los distintos bits del número accediendo a los diferentes miembros (b1->b32), y lo que es mejor, podemos modificarlos (como hacemos al final del programa).
Lo malo de este método es que no podremos acceder a los bits como si de un array se tratase, y que este método no es muy portable, para enteros de 64 bits habría que hacer otro registro por ejemplo, y tendremos problemas para pasar de un sistema big-endian a un little-endian y viceversa; pero, como yo digo podemos ver la memoria directamente, que a veces es interesante.
Últimos comentarios