cap10ibrahim
cap10ibrahim

Reputation: 617

C storing 2 numbers in one byte

u_char  ip_vhl;     /* version << 4 | header length >> 2 */

I can't get it right , how is this done ? can you give me examples on how to use this byte to store these 2 numbers knowing that each one is 4 bit

Upvotes: 1

Views: 1823

Answers (5)

unwind
unwind

Reputation: 400159

If each number is 4 bits, you're going to use the 8-most lower bits of the character. In many cases, this will be all the bits there are.

Do it like so:

ip_vhl = ((version & 15) << 4) | (length & 15);

Assuming version is the one you want in the upper bits, and length is what you want in the lower-most bits. The & 15 makes sure each value only is 4 bits. This is mostly needed for the length value, to avoid overwriting bits dedicated to the version if length is larger than 15. The decimal constant 15 would be written in hex (as 0xf or 0x0f) by many people, it's a matter of style and taste which you find cleaner.

Another way of writing "an integer with the n right-most bits set to 1, and all other set to 0" is ((1 << n) - 1), and since here n = 4 we could use ((1 << 4) - 1), which of course evaluates to 15.

Your code seems to divide length down first and store that, if that's what you want to do you should do it before packing it into the single char, for clarity:

length >>= 2;  /* Convert from bytes to 32-bit words (or whatever). */
ip_vhl = ((version & 15) << 4) | (length & 15);

Upvotes: 5

Eli Iser
Eli Iser

Reputation: 2834

Also, you can resort to a structure with bit fields:

typedef struct s_ip_vhl 
{
    int version : 4;
    int header_length : 4;
} ip_vhl_type;

ip_vhl_type my_ip_vhl;
my_ip_vhl.version = 4;
my_ip_vhl.header_length = 5;
unsigned char byte = *((byte*)(&my_ip_vhl));

Or you can pack the struct with a union with unsigned char to get the entire byte in one go:

typedef union u_ip_vhl
{
    typedef struct s_ip_vhl 
    {
        int version : 4;
        int header_length : 4;
    } ip_vhl_type;
    unsigned char byte;
} ip_vhl_union;

Upvotes: 1

Artyom
Artyom

Reputation: 31281

Version (a) using bit fields

struct entry {
  unsigned char version : 4;
  unsigned char length  : 4;
} ip_vhl;

ip_vhl.version = version;
ip_vhl.length = length;

Version (b) arithmetics

ip_vhl = (version << 4) | (length & 0xF)
version = ip_vhl >> 4;
length  = ip_vhl & 0xf;

Upvotes: 2

ThiefMaster
ThiefMaster

Reputation: 318808

ip_vhl = (version << 4) | (headerlen & 0xf);

Then the byte will look like this:

VVVVHHHH

To get back the original values:

version = ip_vhl >> 4;
headerlen = ip_vhl & 0xf;

Upvotes: 1

xanatos
xanatos

Reputation: 111950

// Here we are trusting that version and length are both < 0xF
unsigned char ip_vhl = (unsigned char)version << 4 | (unsigned char)length;

unsigned char version = ip_vhl >> 4;
unsigned char length = ip_vhl & 0xF;

Upvotes: 1

Related Questions