C++ 将不同的数据类型打包到一个 long 变量中

C++ packing different data types into one long variable

我陷入了一个陷阱,试图将几个变量打包成一个 8 字节长的变量。

基本上,我有几个二进制文件较小的短项目,我需要将它们打包在一起发送到 class,它必须能够将其解压回来。

所以我做了以下内容:

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

然后我创建一个 PACKAGE 类型的变量,它是空的 (0)

PACKAGE pack = 0;

我想使用二进制运算将变量放入该包中,我这样做:

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

它仅适用于 half-good,我计算出我必须得到等于 2526526262902525058

的包的十进制值
0010001100010000000001100100000000000000000000000000110010000010

作为二进制,但是我得到的是 588254914,或者 00100011000100000000111011000010‬ 为二进制 它的尾巴和头部在某种程度上是正确的,但中间部分某处丢失了。

完成后,我仍将以某种方式提取数据。

假设sizeof(unsigned int) != sizeof(unsigned long long),每次移位的左操作数都是错误的类型。每个移位操作都被截断(可能截断为 32 位)。

尝试,例如:

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

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

或:

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

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

注意:好的,实际上每个右手操作数大于左手类型大小的移位操作,以位为单位调用未定义的行为。典型的未定义行为是截断,但标准允许任何其他行为,包括全球热核war。

我宁愿使用 bitfield 结构来表示这种类型(也使用 uint64_t 来确定可用大小):

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

you could even use the uint_least64_t 数据类型中所述,确保您的目标支持它(因为 uint64_t 的可用性在当前的 c++ 标准中是可选的):

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