2010-11-04 12 views
6

Tengo dos bytes, 8 bits octetos, que deben leerse como: [3 bits] [4 bits] [3 bits].2 bytes representan 3 enteros en C

Ejemplo:

unsigned char octet1 = 0b11111111; // binary values 
unsigned char octet2 = 0b00000011; 

como enteros: [7] [15] [7].

¿Alguien me puede dar una pista por dónde empezar?

+6

... ¿por dónde empezar * qué *? – Flinsch

+4

¿Tarea? No hay nada malo con la tarea, pero las preguntas deben marcarse como tales. Ayuda a la comunidad a mejorar sus respuestas para ser más útil. –

+1

Ahora que estoy hablando de eso ... 3 + 4 + 3! = 8 ... – peoro

Respuesta

3

No hay necesidad de poner los dos bytes juntos antes de la extracción de los bits que queremos.

#include <stdio.h> 

main() 
{ 
    unsigned char octet1 = 0b11111111; 
    unsigned char octet2 = 0b00000011; 
    unsigned char n1 = octet1 & 0b111; 
    unsigned char n2 = (octet1 >> 3) & 0b1111; 
    unsigned char n3 = (octet1 >> 7) | (octet2 + octet2); 

    printf("octet1=%u octet2=%u n1=%u n2=%u n3=%u\n", 
       octet1, octet2, n1, n2, n3); 

} 
+1

Una buena manera de no tener que combinar los octetos como una palabra. Creo que habría escrito '(octet2 + octet2)' como 'octet2 << 2' embargo. También esto parece funcionar solo si los bits más altos de 'octet2' siempre son 0. Puede ser mejor' & 0b111' la última expresión para salvarse de futuros problemas. –

+0

Muchas gracias, para mí parece ser el enfoque más directo. Pero desafortunadamente no logré "arreglar" el problema planteado por Jonas, donde los bits más altos no son 0. Lo he intentado: n3 = (octet1 >> 7) | (octet2 << 2); ? - Creo que se suponía que era << 1, en lugar de << 2? –

+1

'unsigned char n3 = (octet1 >> 7 | octet2 << 1) & 0b111;' –

1

Puede usar operaciones booleanas para obtener y establecer los valores individuales.

No está claro qué bits de los octetos que se aplican a los valores, sino que sólo necesitan & (AND bit a bit), | (OR bit a bit), << (desplazamiento a la izquierda) y >> (desplazamiento a la derecha) para hacer esto.

0

Bitfields podría ser una opción. Es posible que deba rellenar su estructura para que los bits se alineen de la forma que desee.

Consulte Bitfields in C++ o busque StackOverflow para C++ y bitfields o puede usar operadores bit a bit como el esquema en las otras respuestas.

3
oct2| oct1 
000011|1 1111 111 
    ---- ---- --- 
    7 0xf 7 

Sólo un consejo, (asumiendo que es la tarea)

1

de inicio de escritura de un embalaje/desembalaje funciones para sus híbridos de 2 bytes.

Si por lo que el trabajo con C++/C - es posible utilizar el apoyo intrínseco a esto:

struct Int3 { 
    int a : 3; 
    int b : 4; 
    int c : 3; 
}; 
2

Nota: 0x11111111 no significa 8 bits todo listo para 1. Es un número hexadecimal de 4 bytes, donde cualquier byte se establece en 0x11.

0xFF es un solo byte (8 bits), donde cualquier bit se pone a 1.

Entonces, para lograr lo que quiere usted podría utilizar algunas macros para aislar los bits que necesita:

#define TOKEN1(x) ((x)>>7) 
#define TOKEN2(x) (((x)>>3) & (0xFF>>5)) 
#define TOKEN3(x) (((x)>>5) & (0xFF>>5)) 

No lo probé.

Otra idea, que podría ser la de poner en una unión un char y una estructura utilizando campo de bits de caracteres

union { 
    struct { char a:3; char b:4; char c:3; }; 
    char x; 
}; 

De esta manera puede utilizar x para editar todo el octeto, y A, B y C a el acceso a las fichas individuales ...

Editar: 3 + 4 + 3 = 8.

Si necesita 10 bits que debe utilizar un corto en lugar de un char. Si, en cambio, algunos de esos bits se superponen, la solución que utiliza MACRO probablemente será más fácil: necesitará más de una estructura dentro de la unión para lograr el mismo resultado con la segunda solución ...

0

¿Quiere decir , si "concatenamos" octetos como octet2.octet1, obtendremos 000000 [111] [1111] [111]?

entonces puede usar operaciones de bits:

  • ">>" y "< <" desplazan los bits en su valor,
  • "&" para enmascarar los bits
  • "+" para combinar valores

Por ejemplo, el valor "medio" (que es de 4 bits de longitud) pueden ser recibidas de la siguiente manera:

middle = 15 & (octet1 >> 3); 
0
assert(CHAR_BIT == 8); 
unsigned int twooctets = (octet2 << 8) | (octet1); /* thanks, Jonas */ 
unsigned int bits0to2 = (twooctets & /* 0b0000_0000_0111 */ 0x007) >> 0; 
unsigned int bits3to6 = (twooctets & /* 0b0000_0111_1000 */ 0x078) >> 3; 
unsigned int bits7to9 = (twooctets & /* 0b0011_1000_0000 */ 0x380) >> 7; 
+2

¿No debería el primero & ser un |? –

+0

Sí, gracias. Código corregido – pmg

9

En una especie de pseudocode

octet1 = 0b11111111 
octet2 = 0b00000011 
word = octet1 | octet2<<8 
n1 = word & 0b111 
n2 = word>>3 & 0b1111 
n3 = word>>7 & 0b111 
+0

Es posible que desee agregar paréntesis para mayor claridad. Si su pseudocódigo es como C, entonces el desplazamiento tiene mayor prioridad que '&' y '|', pero no todos lo saben. – dan04

+0

No estoy tan seguro de que pueda llamarse pseudocódigo en absoluto porque es Ruby. Ruby tiene la misma precedencia más alta para '>>' a '&' y '|' como C. Creo que no debería ser necesario saber que '|' es bitwise o, '&' es bitwise and, y eso '>>' y '<<' bit se desplazan hacia la derecha y hacia la izquierda para leer el seudocódigo. Como un ejemplo de pseudocódigo para un C-programador, podría funcionar. –

+0

Gracias por su muestra, su respuesta recibió la mayor cantidad de votos, pero francamente creo que sería más apropiado seleccionar la que en realidad es una muestra C, y no requiere la tercera asignación de 'palabra' –

4

Hola aquí es un método que se prueba y se compila utilizando VC++ 9

#pragma pack(1) 

union 
{ 
    struct 
    { 
     unsigned short val1:3; 
     unsigned short val2:4; 
     unsigned short val3:3; 
     unsigned short val4:6; 
    } vals; 
    struct 
    { 
     unsigned char octet1:8; 
     unsigned char octet2:8; 
    } octets; 
    short oneVal; 
} u = {0xFFFF}; 

unsigned char octet1 = 0xFF; //1 1111 111 
unsigned char octet2 = 0x03; //000000 11 
//000000 111 1111 111 0 7 15 7 
u.octets.octet1 = octet1; 
u.octets.octet2 = octet2; 
cout << "size of u.vals:" << sizeof(u.vals)<< endl; 
cout << "size of u.octets:" << sizeof(u.octets)<< endl; 
cout << "size of u.oneVal:" << sizeof(u.oneVal)<< endl; 
cout << "size of u:" << sizeof(u)<< endl; 
cout << endl; 

cout << "Your values:" << endl; 
cout << "oneVal in Hex: 0x"; 
cout.fill('0'); 
cout.width(4); 
cout<< hex << uppercase << u.oneVal << endl; 
cout << "val1: " << (int)u.vals.val1 << endl; 
cout << "val2: " << (int)u.vals.val2 << endl; 
cout << "val3: " << (int)u.vals.val3 << endl; 
cout << "val4: " << (int)u.vals.val4 << endl; 
cout << endl; 

octet1 = 0xCC; //1 1001 100 
octet2 = 0xFA; //111110 10 
//111110 101 1001 100 62 5 9 4 
u.octets.octet1 = octet1; 
u.octets.octet2 = octet2; 

cout << "Some other values:" << endl; 
cout << "oneVal in Hex: 0x"; 
cout.fill('0'); 
cout.width(4); 
cout<< hex << uppercase << u.oneVal << endl; 
cout << dec; 
cout << "val1: " << (int)u.vals.val1 << endl; 
cout << "val2: " << (int)u.vals.val2 << endl; 
cout << "val3: " << (int)u.vals.val3 << endl; 
cout << "val4: " << (int)u.vals.val4 << endl; 
cout << endl; 

octet1 = 0xCC; //1 1001 100 
octet2 = 0xFA; //111110 10 
//111110 101 1001 100 62 5 9 4 
u.oneVal = (((unsigned short)octet2) << 8) | (unsigned short)octet1; 
cout << "Some thing diffrent asignment:" << endl; 
cout << "oneVal in Hex: 0x"; 
cout.fill('0'); 
cout.width(4); 
cout<< hex << uppercase << u.oneVal << endl; 
cout << dec; 
cout << "val1: " << (int)u.vals.val1 << endl; 
cout << "val2: " << (int)u.vals.val2 << endl; 
cout << "val3: " << (int)u.vals.val3 << endl; 
cout << "val4: " << (int)u.vals.val4 << endl; 
cout << endl; 

en cuenta también que I utiliza #pragma pack (1) para fijar el embalaje estructura a 1 byte .

También incluí una forma de asignar los dos octetos en un valor corto. Lo hice usando el cambio a nivel de bit "< <" y bitwise o "|"

Puede simplificar el acceso a u abandonando las estructuras nombradas. Pero quería mostrar los tamaños que se usan para las estructuras.

De esta manera:

union 
{ 
    struct 
    { 
     unsigned short val1:3; 
     unsigned short val2:4; 
     unsigned short val3:3; 
     unsigned short val4:6; 
    }; 
    struct 
    { 
     unsigned char octet1:8; 
     unsigned char octet2:8; 
    }; 
    short oneVal; 
} u = {0xFFFF}; 

acceso pueda ahora ser tan simple como

u.oneVal = 0xFACC; 

o

u.octet1 = 0xCC; 
u.octet2 = 0xFA; 

también se puede colocar ya sea oneVal o octet1 y octet2 dependiendo de lo que el acceso método que te gusta

+1

Sabes que estás cansado cuando "Esto se hizo usando la mierda bit a bit" te hace reír. –

+0

@Jonas gracias por el lugar. Se corrigió que debería ser "¿Lo hizo usando el desplazamiento a nivel de bit" :)? –

+0

Sí, esta es la forma más obvia de hacerlo en C (para alguien que lee el código de todos modos). – Christoffer