enteros de 12 bits

Iniciado por integeroverflow, 2 Marzo 2017, 08:05 AM

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

integeroverflow

hola que tal. a ver si me pueden dar una mano con esto...

resulta que estoy programando una especie de driver para sistemas de archivos FAT12, basicamente es un programa en C al que le pasamos como parametro la imagen de un floppy y este se encarga de leer y escribir datos en el utilizando el formato FAT12.

como sabran, este formato cuenta con 2 FATS (File Allocation Table) donde se guarda la informacion de todos los clusters presentes en el disco, vendria a ser un array de digitos de 12 bits que puede representar los siguientes valores: cluster sin uso - cluster da;ado - siguiente cluster del archivo - ultimo cluster del archivo.

para leer la FAT lo que hago es calcular el inicio de esta y ir leyendo de a pedazos de 3 bytes (24 bits, 2 entradas de 12 bits). la idea ahroa es partir esos 3 bytes en 2 enteros de 12 bits que me van a dar la informacion de los 2 clusters que se guarda en esos 3 bytes. no hay ningun tipo de datos de 12 bit en C, asi que se me ocurrio usar dos enteros de 16 bits (uint16_t).

lo que necesito hacer es: en el primer entero, copiar la segunda mitad del segundo byte + todo el contenido del primero. en el segundo entero, copiar todo el contenido del tercer byte + la segunda mitad del segundo. esto me daria como resultado las 2 entradas que necesito leer de la FAT.

algo asi:
// (pongo una letra al inicio cada 4 bits para poder apreciar bien lo que neceisto hacer
a110 b011   // byte 0
c100 d100   //  byte 1
e101 f101   // byte 2

esos 3 bytes son los que leo de la fat, ahora neceisto partirlos en 2 enteros de 16 bits, quedando:

c100 a110 b011 0000 // primer entero
d100 e101 f101 0000 // segundo entero

la pregunta es, como puedo realizar esta operacion?

es decir, que operaciones binarias debo realizar?




ivancea96

Los únicos operadores que necesitarás, en principio, son los de desplazamiento de bits (<<, >>) y and (&).

Suponiendo que tengas los 24 bits en un array de 3 chars:

char arr[3]; // 2 enteros de 12 bits
short a, b; // Salida

// Suponiendo que 'a' sea el primer byte y mitad del segundo, pues:

a = (((short)arr[0]) << 4) | (arr[1] >> 4);


Y el resto, más de lo mismo.

integeroverflow

Cita de: ivancea96 en  2 Marzo 2017, 08:51 AM
Los únicos operadores que necesitarás, en principio, son los de desplazamiento de bits (<<, >>) y and (&).

Suponiendo que tengas los 24 bits en un array de 3 chars:

char arr[3]; // 2 enteros de 12 bits
short a, b; // Salida

// Suponiendo que 'a' sea el primer byte y mitad del segundo, pues:

a = (((short)arr[0]) << 4) | (arr[1] >> 4);


Y el resto, más de lo mismo.

que tal amigo, gracias por tu respuesta.
a ver si me ayudas un poco a entender el codigo.

suponiendo que:
arr[0] = 0110 1010
arr[1] = 1100 0001

((short)arr[0])    //casteando a short nos quedaria el byte dentro de 2 bytes, es asi?
0000 0000 0110 1010 // quedando este valor
"<< 4" desplazaria los bits 4 veces hacia la izquierda, correcto?
0000 1010 0110 0000 // quedando este valor

arr[1] >> 4 // desplazaria los bits 4 veces hacia la derecha, quedando este valor:
0000 1100 0000 0000

aplicando '|' entre los dos valores:

0000 0000 0110 1010
0000 1100 0000 0000
//resultado:
0000 1100 0110 1010

entendi bien? si no es asi, podrias explicarme paso a paso como funcionan estas operaciones?

ivancea96

Am casi pero:
arr[1] >> 4 // desplazaria los bits 4 veces hacia la derecha, quedando este valor:
0000 1100 0000 0000

Eso no es así. 1100 0001, desplazando a la derecha, queda: 0000 1100
Con lo cual, 0000 1010 0110 0000 | 0000 1100 == 0000 1010 0110 1100

integeroverflow

Cita de: ivancea96 en  2 Marzo 2017, 13:09 PM
Am casi pero:
arr[1] >> 4 // desplazaria los bits 4 veces hacia la derecha, quedando este valor:
0000 1100 0000 0000

Eso no es así. 1100 0001, desplazando a la derecha, queda: 0000 1100
Con lo cual, 0000 1010 0110 0000 | 0000 1100 == 0000 1010 0110 1100

ya veo, gracias.

para tratar de entender un poco mejor esto, si quiero partir  un short en 2 bytes, seria correcto hacer esto?

short a = X; // digamos que vale: 1101 1110 0101 1010
char b[2];
b[0] = (a >> 8); // quedaria 0000 0000 1101 1110
b[1] = (a << 8) >> 8; // primero quedaria:  0101 1010 0000 0000
// y despues se convierte a: 0000 0000 0101 1010

es correcto?

gracias por tu ayuda




ivancea96

Correcto.
Como detalle extra, en vez de (x << 8) >> 8, puedes hacer x & 0xFFFF.

integeroverflow

Cita de: ivancea96 en  2 Marzo 2017, 14:45 PM
Correcto.
Como detalle extra, en vez de (x << 8) >> 8, puedes hacer x & 0xFFFF.

mmm, eso no me quedo muy claro.

digamos que el short vale 1101 1001 1100 1000.

si desplazo 8 hacia la derecha, obtengo el primer byte:
0000 0000 1100 1000

para obtener el segundo, vos decis que haga and con 0xFFFF, que en binario sera 1111 1111 1111 1111, resultando:

  1101 1001 1100 1000
  1111 1111 1111 1111
=1101 1001 1100 1000

es decir, el mismo numero.
no habras querido decir 0xFF?
en ese caso, 0xFF valdria 0000 0000 1111 1111
y el resultado del and seria

   1101 1001 1100 1000
   0000 0000 1111 1111
= 0000 0000 1100 1000
dando el ultimo byte.

o quizas me equivoco.

gracias por tu ayuda, ya voy entendiendo como se opera con bits.



ivancea96

Oh sí, me confundí. 0xFF.

Borito30

#8
Cita de: integeroverflow en  2 Marzo 2017, 12:43 PM
que tal amigo, gracias por tu respuesta.
a ver si me ayudas un poco a entender el codigo.

suponiendo que:
arr[0] = 0110 1010
arr[1] = 1100 0001

((short)arr[0])    //casteando a short nos quedaria el byte dentro de 2 bytes, es asi?
0000 0000 0110 1010 // quedando este valor
"<< 4" desplazaria los bits 4 veces hacia la izquierda, correcto?
0000 1010 0110 0000 // quedando este valor

arr[1] >> 4 // desplazaria los bits 4 veces hacia la derecha, quedando este valor:
0000 1100 0000 0000

aplicando '|' entre los dos valores:

0000 0000 0110 1010
0000 1100 0000 0000
//resultado:
0000 1100 0110 1010

entendi bien? si no es asi, podrias explicarme paso a paso como funcionan estas operaciones?


Hola no entiendo esto.
A ver tu tienes un array ejemplo:
int arr [2];

Y le asignas dos valores:
arr[0] = 0110 1010
arr[1] = 1100 0001

((short)arr[0])    //casteando a short nos quedaria el byte dentro de 2 bytes, es asi?

Eso quiere decir que tu cadena se alarga en 16 bits.

Pero porqué este valor?
0000 0000 0110 1010 // quedando este valor


Aqui dices esto:
"<< 4" desplazaria los bits 4 veces hacia la izquierda, correcto?
0000 1010 0110 0000 // quedando este valor


Pero lo correcto seria¿Porque este número de donde lo sacaron?:
0000 1100 0000 0000

Lo usastes en la posicion 1¿?
arr[1] >> 4

Y porque devuelve este valor?:
0000 1100 0000 0000

Aplicando esto:
0000 0000 0110 1010 | 0000 1100 0000 0000

Cuanto devolvería y porque? A vale es una division ok.
En cuanto esto sería una simple suma es correcto?
  1101 1001 1100 1000
  0000 0000 1111 1111
= 0000 0000 1100 1000

Hace tiempo que no repasaba las operaciones en binario tendré que repasarlas si me podeis aclarar alguno de estos puntos me seria util gracias.

Por otro lado porque
0xFF valdria 0000 0000 1111 1111 ?

Estoy en contra del foro libre y la Sección de juegos y consolas (distraen al personal)

ivancea96

Oh, un detalle más. El array, en vez de char, debería ser de unsigned char (sinó, si el valor coincide negativo, la transformación a short será negativa y no serviría.

Bueno, estaba revisando el tema, y la colocación de los bits puede que la haya interpretado al revés.

Puedes testear con:

#include <stdio.h>

void printBinary(void* address, unsigned int bytes){
//for(int i=0; i<bytes; i++){
for(int i=bytes - 1; i>=0; i--){
int mask = 1 << 7;
do{
printf("%c", (((char*)address)[i] & mask? '1' : '0'));
mask >>= 1;
}while(mask);

//if(i+1 < bytes)
if(i-1 >= 0)
printf(" ");
}
}

int main(){
unsigned char arr[2];
arr[0] = 0b01101010; // 00000110 10101100
arr[1] = 0b11000001; // 00001100

short result = (((short)arr[0]) << 4) | (arr[1] >> 4);

printBinary(&arr[0], 1);
printf("\n");
printBinary(&arr[1], 1);
printf("\n");
printBinary(&result, 2);
printf("\n");
}


Si arr[0] = AB y arr[1] = CD, la salida es ABC.
No es lo que pusiste tú al principio, pero bueno, el cambio es mínimo. Perdona la confusión :p

CitarPor otro lado porque
0xFF valdria 0000 0000 1111 1111 ?
Am no sé cómo responder a esto. Es así. Hexadecimal a binario.