Acceder a bits de un array.

Iniciado por 0xDani, 23 Octubre 2012, 16:27 PM

0 Miembros y 1 Visitante están viendo este tema.

0xDani

¿Es correcta esta forma de acceder a los bits de un array?

_Bool bit(char *a, int b)
{
  int index = (b/8)-1;
  if(b%8) index++;
  if((a[index]>>(8-(b%8)))%2) return true;
  return false;
}


a es un puntero a un array de chars a cuyos bits se quiere acceder y b el numero del byte al que se quiere acceder.
Seguramente se puede hacer mas facil, ultimamente he tenido examenes y ando un poco espeso xD

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

rir3760

El desplazamiento dentro del byte depende de como lo interpretes lo usual es no hacerlo. Esa función se puede acortar un poco. Por ejemplo:
#include <stdio.h>
#include <stdlib.h> /* div_t, div */
#include <limits.h> /* CHAR_BIT */

_Bool bit(unsigned char *a, int pos);

int main(void)
{
   unsigned char test = 131;
   int i;
   
   for (i = CHAR_BIT - 1; i >= 0; i--)
      printf("%2d", i);
   putchar('\n');
   for (i = CHAR_BIT - 1; i >= 0; i--)
      printf("%2d", bit(&test, i));
   putchar('\n');
   
   return EXIT_SUCCESS;
}

_Bool bit(unsigned char *a, int pos)
{
   div_t d = div(pos, CHAR_BIT); /* .quot = byte, .rem = bit */
   
   return a[d.quot] >> d.rem & 1;
}


Y su salida (con lo usual, ocho bits por byte) es:
7 6 5 4 3 2 1 0
1 0 0 0 0 0 1 1


Otra opción es utilizar directamente los operadores de división y modulo.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

0xDani

Cita de: rir3760 en 23 Octubre 2012, 17:50 PM
El desplazamiento dentro del byte depende de como lo interpretes lo usual es no hacerlo. Esa función se puede acortar un poco. Por ejemplo:
#include <stdio.h>
#include <stdlib.h> /* div_t, div */
#include <limits.h> /* CHAR_BIT */

_Bool bit(unsigned char *a, int pos);

int main(void)
{
   unsigned char test = 131;
   int i;
   
   for (i = CHAR_BIT - 1; i >= 0; i--)
      printf("%2d", i);
   putchar('\n');
   for (i = CHAR_BIT - 1; i >= 0; i--)
      printf("%2d", bit(&test, i));
   putchar('\n');
   
   return EXIT_SUCCESS;
}

_Bool bit(unsigned char *a, int pos)
{
   div_t d = div(pos, CHAR_BIT); /* .quot = byte, .rem = bit */
   
   return a[d.quot] >> d.rem & 1;
}


Y su salida (con lo usual, ocho bits por byte) es:
7 6 5 4 3 2 1 0
1 0 0 0 0 0 1 1


Otra opción es utilizar directamente los operadores de división y modulo.

Un saludo

Gracias por la respuesta, muy buena.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

xiruko

#3
una pregunta que es lo que quieres hacer exactamente? modificar los bits de un byte? esto se suele hacer aplicando mascaras al byte. por ejemplo, si tienes un byte inicial:
a = 10000001
y quieres poner a 0 el MSB para que quede asi:
b = 00000001
lo que deberias hacer es aplicar la siguiente mascara:
b = a & 0x7F
con lo que estarias poniendo a 0 el bit mas significativo, y dejando igual a los demas. si ahora quisieras volver a ponerlo a 1, deberias aplicar la siguiente mascara:
c = b | 0x80

lo digo porque no creo que hagan falta librerias externas y demas para acceder a los bits, ya que con los operadores que trae hay mas que suficiente para muchisimas aplicaciones. si tienes alguna pregunta ya diras...

espero que te sirva de ayuda, un saludo!

0xDani

Cita de: xiruko en 23 Octubre 2012, 23:43 PM
una pregunta que es lo que quieres hacer exactamente? modificar los bits de un byte? esto se suele hacer aplicando mascaras al byte. por ejemplo, si tienes un byte inicial:
a = 10000001
y quieres poner a 0 el MSB para que quede asi:
b = 00000001
lo que deberias hacer es aplicar la siguiente mascara:
b = a & 0x7F
con lo que estarias poniendo a 0 el bit mas significativo, y dejando igual a los demas. si ahora quisieras volver a ponerlo a 1, deberias aplicar la siguiente mascara:
c = b | 0x80

lo digo porque no creo que hagan falta librerias externas y demas para acceder a los bits, ya que con los operadores que trae hay mas que suficiente para muchisimas aplicaciones. si tienes alguna pregunta ya diras...

espero que te sirva de ayuda, un saludo!

stdlib es una libreria del estandar, no es nada externo. Y si tengo una pregunta, ¿de donde sacas las mascaras? Si no utilizo ni siquiera la libreria del estandar pues mejor.

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM

xiruko

Citarstdlib es una libreria del estandar, no es nada externo.

cierto, no lo dije como deberia haberlo hecho. me referia mas bien a que no hace falta usar ninguna libreria para hacer esto que comentas.

CitarY si tengo una pregunta, ¿de donde sacas las mascaras?

no se si lo sabras, pero para pasar de binario a hexadecimal se cogen los bits en grupos de 4 (por lo que tienes un valor de 0 a 15 para cada agrupacion) y se pasa directamente al caracter hexadecimal. por ejemplo:

decimal: 12 -> binario: 0000(0) 1100(12 = C hex) -> hexadecimal: 0x0C
decimal: 67 -> binario: 0100(4) 0011(3) -> hexadecimal: 0x43
decimal: 179 -> binario: 1011(11 = B hex) 0011(3) -> hexadecimal: 0xB3


luego en cuanto a las mascaras, las mas simples son una AND (&) o una OR (|). para una AND, el resultado sera cierto (1) solo si los dos operandos son 1, y para los demas casos sera 0. en cuanto a la OR, solo sera falso (0) cuando los dos operandos son 0, y en cualquier otro caso sera 1.

te pondre un par de ejemplos mas:

si tienes un numero inicial 01100110 (102 en decimal), y quieres poner a 0 el bit 1 y 2 (en binario, el bit menos significativo es el de la derecha de todo y se considera el bit 0), entonces deberas aplicar una mascara AND con un numero que en esas posiciones tenga los bits en 0, y en todas las restantes tenga 1 para no alterar nada, ya que un AND con un 1 hara que el resultado siga como estaba, puesto que si estaba en 1 seria: 1&1=1 y si estaba en 0 seria: 1&0=0. por lo tanto, el numero que debemos usar para la mascara seria el 11111001, que es el 0xF9 en hexadecimal.
a=01100110
a&=0xF9 (a vale 01100000)


ahora imagina que quieres poner el bit 4 a 1, lo que deberias hacer es aplicar una mascara OR con un numero que tenga el bit en 1 en esa posicion, y las demas en 0 para no alterar nada mas, ya que si el bit estaba en 0: 0|0=0 y si estaba en 1: 1|0=1. este numero seria el 00010000, que es el 0x10 en hexadecimal.
a|=0x10 (a vale 01110000)

con esto y el operador shift (<< o >>) se pueden hacer infinidad de cosas a nivel de bits. la mas simple de todas, un simple programa que te pase de decimal a binario sin divisiones ni restos. (compila con un warning pero funciona bien, me daba pereza buscar el especificador de formato adecuado):

#include <stdio.h>

int main() {

unsigned char byte;
short int i;

printf("Ingresa un numero del 0-255: ");
scanf("%u", &byte);

for (i=7; i>=0; i--)
printf("%u", (byte>>i)&0x01);
printf("\n");

return 0;
}


con su salida:

:~$ ./dec2bin
Ingresa un numero del 0-255: 23
00010111


espero que te ayude, un saludo!

0xDani

Umm... no se como no lo he pensado xD. Perdon por haberte hecho escribir tanto, y gracias por las respuestas. En cuanto a las mascaras, creia que te referias a los valores hexadecimales, ya conocia los operadores de bits.

Saludos.
I keep searching for something that I never seem to find, but maybe I won't, because I left it all behind!

I code for $$$
Hago trabajos en C/C++
Contactar por PM