Search code examples
c++binarypacking

C++ packing different data types into one long variable


I've got into a trap trying to pack a couple of variables into a one variable 8 byte long.

Basically, I've got a couple of short items which have small binary size and I need to pack them together to send into class which must be able to depack it back.

So I made the following:

typedef unsigned long long PACKAGE; // 8 byte (shows as _int64 in debug)
(sizeof returns '8')
unsigned int dat1   = 25;  // 1 byte long max
unsigned int dat2   = 1;   // 4 bit long max
unsigned int dat3   = 100; // 2 byte long max
unsigned int dat4   = 200; // 4 byte long max
unsigned int dat5   = 2;   // 4 bit long max

Then I make a variable of PACKAGE type which is empty (0)

PACKAGE pack = 0;

And I want to throw variables into that pack using binary operations, I do:

pack = (dat1 << 56) | (dat2 << 52) | (dat3 << 36) | (dat4 << 4) | dat5;

it works only half-good, I calculated that I must get decimal value of pack equals to 2526526262902525058, or

0010001100010000000001100100000000000000000000000000110010000010

as binary, however istead I'm getting 588254914, or ‭00100011000100000000111011000010‬ as binary which is somehow correct at it's tail and head but the middle part is missing off somewhere.

And when this is done I'm still about to extract the data back somehow.


Solution

  • I'd rather use a bitfield struct to represent such type (also use uint64_t to be sure of the available size):

    union PACKAGE {
        struct bits {
            uint64_t dat1 : 8;  // 1 byte long max
            uint64_t dat2 : 4;  // 4 bit long max
            uint64_t dat3 : 16; // 2 byte long max
            uint64_t dat4 : 32; // 4 byte long max
            uint64_t dat5 : 4;  // 4 bit long max
        };
        uint64_t whole; // for convenience
    };
    

    As mentioned in comments you could even use the uint_least64_t data type, to ensure your target supports it (since availability of uint64_t is optional from the current c++ standard):

    union PACKAGE {
        struct bits {
            uint_least64_t dat1 : 8;  // 1 byte long max
            uint_least64_t dat2 : 4;  // 4 bit long max
            uint_least64_t dat3 : 16; // 2 byte long max
            uint_least64_t dat4 : 32; // 4 byte long max
            uint_least64_t dat5 : 4;  // 4 bit long max
        };
        uint_least64_t whole; // for convenience
    };