user1461001
user1461001

Reputation: 703

combine a byte into long long

I have a int64 (which is a long long) value and a byte value. I want to merge them together. i know that my long long value doesn't use 64 bits. So i want to use the unset 8 bits (most significant or least significant?) to encode a byte into it.

Later on i want to seperate them to find the original value and the byte.

so preferably functions or a macros of sort

typedef unsigned char byte;
typedef long long int64;

int64 make_global_rowid(int64 rowid, byte hp_id);

byte get_hp_id(int64 global_row_id);

int64 get_row_id(int64 global_row_id);

get_hp_id seperates and returns the byte from the merged value, while the get_row_id returns the original int64 which was merged with the byte

Upvotes: 1

Views: 277

Answers (3)

Ingo Leonhardt
Ingo Leonhardt

Reputation: 9894

Just a hint about bit operations in C:

   int i = 0x081500; //lsb is 0x00
   char b = '\x12';   //any byte
   char r;

   i = i | ( b & 0xff );     // will be 0x081512
   r = i & 0xff;  // again 0x12, equal to r

   i = i | ( (b & 0xff) << 16 ); // will be 0x120815000 because first b is shifted 16 bits (--> 0x120000)
   r = ( i >> 16 ) & 0xff;  // first i is shifted to 0x12, then use lsb
   /* important: this expects i >= 0 */

Same works with long or long long as well of course. I hope that helps you to understand how to use bit operations.

Upvotes: 0

ChristopheLec
ChristopheLec

Reputation: 856

You can use bitwise operators to achieve this. Let's say you want to sacrifice the 8 most significant bits in your long long. (Be careful if your long long is negative ! The sign is stored as the most significant bit, so you'll lose the sign !)

Now, to do this, you can do :

byte get_hp_id(int64 global_row_id)
{
  return ((char)global_row_id);
}

int64 get_row_id(int64 global_row_id)
{
  return (global_row_id >> 8);
}

int64 make_global_rowid(int64 rowid, byte hp_id)
{
  return (rowid << 8 + hp_id)
}

For the little explanation, << is a bitshifting operator. What it does is that it shifts all your bits either right or left. Bits that goes out of boundaries are lost, and bits coming from nowhere are set to 0 :

 1001001 << 2 == 0100100 // the first 1 is lost, and 2 "0" come from the right

In your case, we shift to the right of 8 bits (to leave space for your byte), and therefore the 8 most significant bits are lost forever. But now, we have something like :

(xxxxxxxx)(xxxxxxxx)(xxxxxxxx)(00000000)

Which means that we can add anything fitting in 8 bits without modifying the original value. And tada ! We have stored a byte in a long long !

Now, to extract the byte, you can just cast it as a char. During the cast, only the 8 least significant bits are saved (your byte).

And finally, to extract your long long, you just have to shift the bits the other way around. The byte will be overwritten, and your long long will be as good as new !

Upvotes: 3

Sergey L.
Sergey L.

Reputation: 22542

for the sake of ease of use I would use a union:

union longlong_and_byte {
    long long long_value;
    char char_values[8];
};

union longlong_and_byte test;

test.long_value = 4000;

// for little endian (x86 for example) the most significant byte is the last one
test.char_values[7] = 19;

// for big endian (PPC for example) the most significant byte is the first one
test.char_values[0] = 19;


printf("long long value is %ld\nchar value is %d\n"
, test.long_value & 0xFFFFFFFFFFFFFF // need to mask off the necessary bits, only works with unsigned
, test.char_values[7]
);

Upvotes: 0

Related Questions