2 байта представляют 3 целых числа в C - PullRequest
6 голосов
/ 04 ноября 2010

У меня есть два байта, 8-битные октеты, которые должны читаться как: [3 бита] [4 бита] [3 бита].

Пример:

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

в виде целых чисел: [7] [15] [7].

Кто-нибудь может подсказать, с чего начать?

Ответы [ 10 ]

9 голосов
/ 04 ноября 2010

В виде псевдокода

octet1 = 0b11111111
octet2 = 0b00000011
word = octet1 | octet2<<8
n1 = word & 0b111
n2 = word>>3 & 0b1111
n3 = word>>7 & 0b111
4 голосов
/ 04 ноября 2010

Привет, вот метод, который протестирован и скомпилирован с использованием 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;

Также обратите внимание, что я использую # pragma pack (1) для установки структуры упаковки на1 байт.

Я также включил способ назначения двух октетов в одно короткое значение.Сделал это с помощью побитового сдвига «<<» и побитового или «|» </p>

Вы можете упростить доступ к вам, отбросив названные структуры.Но я хотел показать размеры, которые используются для структур.

Например:

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};

Доступ теперь будет таким же простым, как

u.oneVal = 0xFACC;

или

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

, вы также можете сбросить либо oneValили octet1 и octet2 в зависимости от того, какой метод доступа вам нравится.

3 голосов
/ 04 ноября 2010

Нет необходимости соединять два байта перед извлечением нужных нам битов.

#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);

}
3 голосов
/ 04 ноября 2010
  oct2|  oct1
000011|1 1111 111
    ---- ---- ---
     7   0xf   7

Просто подсказка, (при условии, что это домашняя работа)

2 голосов
/ 04 ноября 2010

Примечание : 0x11111111 не означает, что все 8 бит установлены в 1. Это шестнадцатеричное число из 4 байтов, где любой байт имеет значение 0x11.

0xFF - это один байт(8 бит), где любой бит установлен в 1.

Затем, чтобы достичь того, что вы хотите, вы можете использовать несколько MACRO для выделения нужных бит:

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

DidnПротестируйте его.

Другая идея, возможно, заключалась в том, чтобы вставить объединение char и структуры с использованием битовых символов

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

Таким образом, вы можете использовать x для редактированиявесь октет и a, b и c для доступа к одиночным токенам ...

Изменить : 3 + 4 + 3! = 8.

Если вынужно 10 бит, вы должны использовать короткий вместо символа.Если вместо этого некоторые из этих битов перекрываются, решение с использованием MACRO, вероятно, будет проще: вам потребуется более одной структуры внутри объединения, чтобы достичь того же результата со вторым решением ...

1 голос
/ 04 ноября 2010

Начните с написания функций упаковки / распаковки для ваших 2-байтовых гибридов.

Если вы так работаете с C / C ++ - вы можете использовать встроенную поддержку для этого:

struct Int3 {
    int a : 3;
    int b : 4;
    int c : 3;
};
1 голос
/ 04 ноября 2010

Вы можете использовать логические операции для получения и установки отдельных значений.

Неясно, какие биты ваших октетов применяются к каким значениям, но вам нужно только & (поразрядное И), | (поразрядное)ИЛИ), << (сдвиг влево) и >> (сдвиг вправо), чтобы сделать это.

0 голосов
/ 04 ноября 2010
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;
0 голосов
/ 04 ноября 2010

Вы имеете в виду, если мы "объединяем" октеты как octet2.octet1, мы получим 000000 [111] [1111] [111]?

Тогда вы можете использовать битовые операции:

  • ">>" и "<<" для сдвига битов в вашем значении, </li>
  • "&" для маскирования битов
  • "+" для объединения значений

Например, «среднее» значение (длиной 4 бита) может быть получено следующим образом:

middle = 15 & (octet1 >> 3);
0 голосов
/ 04 ноября 2010

Битовые поля могут быть одним из вариантов. Возможно, вам придется дополнить вашу структуру, чтобы биты выстроились так, как вы хотите.

См. Битовые поля в C ++ или выполните поиск StackOverflow для C ++ и битовых полей, или вы можете использовать побитовые операторы в качестве схемы в других ответах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...