Doori Bar
Doori Bar

Reputation: 903

2 bytes represent 3 integers in C

I have two bytes, 8 bit octets, which should be read as: [3 bits][4 bits][3 bits].

Example:

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

As integers: [7][15][7].

Anybody can give me a hint where to start?

Upvotes: 6

Views: 559

Answers (10)

Alien_SM
Alien_SM

Reputation: 145

Hi here is a method that is tested and compiled using 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;

Also note that I uses #pragma pack( 1 ) to set the structure packing to 1 byte.

I also included a way of assigning the two octets into the one short value. Did this using bitwise shift "<<" and bitwise or "|"

You can simplify the access to u by dropping the named structures. But I wanted to show the sizes that is used for the structures.

Like this:

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

Access would now be as simple as

u.oneVal = 0xFACC;

or

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

you can also drop either oneVal or octet1 and octet2 depending on what access method you like.

Upvotes: 4

Jonas Elfstr&#246;m
Jonas Elfstr&#246;m

Reputation: 31438

In a kind of pseudocode

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

Upvotes: 9

pmg
pmg

Reputation: 108978

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;

Upvotes: 0

kriss
kriss

Reputation: 24197

No need to put the two bytes together before extracting bits we want.

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

}

Upvotes: 3

Kel
Kel

Reputation: 7790

Do you mean, if we "concatenate" octets as octet2.octet1, we will get 000000[111][1111][111]?

Then you may use bit operations:

  • ">>" and "<<" to shift bits in your value,
  • "&" to mask bits
  • "+" to combine values

For example, "middle" value (which is 4-bits-length) may be received in the following way:

middle = 15 & (octet1 >> 3);

Upvotes: 0

peoro
peoro

Reputation: 26060

Note: 0x11111111 doesn't mean 8 bits all set to 1. It's an hexadecimal number of 4 bytes, where any byte is set to 0x11.

0xFF is a single byte (8 bit) where any bit is set to 1.

Then, to achieve what you want you could use some MACROs to isolate the bits you need:

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

Didn't test it.

Another idea, could be that of putting in an union a char and a struct using bitfield chars

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

This way you can use x to edit the whole octet, and a, b and c to access to the single tokens...

Edit: 3+4+3 != 8.

If you need 10 bits you should use a short instead of a char. If, instead, some of those bits are overlapping, the solution using MACRO will probably be easier: you'll need more than one struct inside the union to achieve the same result with the second solution...

Upvotes: 2

valdo
valdo

Reputation: 12943

Start from writing a packing/unpacking functions for your 2-byte hybrids.

If you so the work with C/C++ - you may use the intrinsic support for this:

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

Upvotes: 1

stacker
stacker

Reputation: 68972

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

Just a hint,(assuming it is homework)

Upvotes: 3

Andrew Cash
Andrew Cash

Reputation: 2394

Bitfields could be one option. You may need to pad your struct to get the bits to line up the way you want them to.

Refer to Bitfields in C++ or search StackOverflow for C++ and bitfields or you can use bitwise operators as outline in the other answers.

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 882028

You can use boolean opeations to get and set the individual values.

It's unclear which bits of your octets apply to which values but you only need & (bitwise AND), | (bitwise OR), << (left shift) and >> (right shift) to do this.

Upvotes: 1

Related Questions