C ++ 64位整数位

时间:2012-06-15 03:35:54

标签: c++ bitwise-operators

你好我这里有一个7字节的结构,我想把它写成64位整数。接下来,我想稍后从64位整数中提取出这个结构。

有关于此的任何想法吗?

#include "stdafx.h"

struct myStruct
{
        unsigned char a;               
        unsigned char b;
        unsigned char b;
        unsigned int someNumber;
};

int _tmain(int argc, _TCHAR* argv[])
{
    myStruct * m = new myStruct();
    m->a = 11;
    m->b = 8;
    m->c = 12;
    m->someNumber = 30;

    printf("\n%s\t\t%i\t%i\t%i\t%i\n\n", "struct", m->a, m->b, m->c, m->someNumber);

    unsigned long num = 0;

    // todo: use bitwise operations from m into num (total of 7 bytes) 

    printf("%s\t\t%i\n\n", "ulong", num);

    m = new myStruct();

    // todo: use bitwise operations from num into m;

    printf("%s\t\t%i\t%i\t%i\t%i\n\n", "struct", m->a, m->b, m->c, m->someNumber);

    return 0;
}

3 个答案:

答案 0 :(得分:1)

你应该这样做:

class structured_uint64
{
    uint64_t data;
public:
    structured_uint64(uint64_t x = 0):data(x) {}
    operator uint64_t&() { return data; }
    unsigned uint8_t low_byte(size_t n) const { return data >> (n * 8); }
    void low_byte(size_t n, uint8_t val) {
        uint64_t mask = static_cast<uint64_t>(0xff) << (8 * n);
        data = (data & ~mask) | (static_cast<uint64_t>(val) << (8 * n));
    }
    unsigned uint32_t hi_word() const { return (data >> 24); }
    // et cetera
};

(当然,有很多空间可以让界面的细节发生变化,64位成分的位置也是如此)

使用不同的类型来对同一部分内存进行别名是一个坏主意。问题是,优化器能够使用如下推理非常有价值:

  

“好的,我在这个块的开头读过一个uint64_t,并且程序中间没有任何地方写入任何uint64_t,因此值必须保持不变!”

这意味着如果您尝试通过uint64_t引用更改uint32_t对象的值,则会得到错误的答案。因为这非常依赖于可能和完成的优化,实际上很容易在测试用例中遇到问题,但是在你尝试编写的真实程序中看到它 - 你会花费很多时间来尝试找到这个错误,因为你确信自己并不是这个问题。

所以,你真的应该用bit twiddling(或内在函数,如果分析表明这是一个性能问题并且有可用的有用的那些)来插入/提取字段,而不是试图设置一个聪明的结构。 / p>

如果你真的知道你正在做什么,你可以让别名工作,我相信。但只有当你真的知道你正在做什么时才应该这样做,这包括从内到外了解标准中的相关规则(我不知道,所以我不能建议你关于如何使它工作)。即便如此,你可能不应该这样做。

此外,如果您打算将整数类型设置为特定大小,则确实使用正确的类型。例如,永远不要将unsigned int用于一个应该是32位的整数。而是使用uint32_t。它不仅是自我记录的,而且当您尝试在unsigned int 32位的环境中构建程序时,您不会遇到令人讨厌的意外。

答案 1 :(得分:0)

使用unionunion的每个元素占用相同的地址空间。 struct是一个元素,unsigned long long是另一个元素。

#include <stdio.h>

union data
{
    struct
    {
        unsigned char a;
        unsigned char b;
        unsigned char c;
        unsigned int d;
    } e;
    unsigned long long f;
};

int main()
{
    data dat;
    dat.f = 0xFFFFFFFFFFFFFFFF;
    dat.e.a = 1;
    dat.e.b = 2;
    dat.e.c = 3;
    dat.e.d = 4;
    printf("f=%016llX\n",dat.f);
    printf("%02X %02X %02X %08X\n",dat.e.a,dat.e.b,dat.e.c,dat.e.d);
    return 0;
}

输出,但请注意原始unsigned long long的一个字节仍然存在。编译器喜欢在可被4整除的地址上对齐数据,例如4字节整数,因此是三个字节,然后是填充字节,因此整数位于偏移4处,struct的总大小为8。

f=00000004FF030201
01 02 03 00000004

这可以以编译器相关的方式进行控制。以下是Microsoft C ++:

#include <stdio.h>

#pragma pack(push,1)
union data
{
    struct
    {
        unsigned char a;
        unsigned char b;
        unsigned char c;
        unsigned int d;
    } e;
    unsigned long long f;
};
#pragma pack(pop)

int main()
{
    data dat;
    dat.f = 0xFFFFFFFFFFFFFFFF;
    dat.e.a = 1;
    dat.e.b = 2;
    dat.e.c = 3;
    dat.e.d = 4;
    printf("f=%016llX\n",dat.f);
    printf("%02X %02X %02X %08X\n",dat.e.a,dat.e.b,dat.e.c,dat.e.d);
    return 0;
}

注意struct现在占用7个字节,unsigned long long的最高字节现在不变:

f=FF00000004030201
01 02 03 00000004

答案 2 :(得分:0)

知道了。

static unsigned long long compress(char a, char b, char c, unsigned int someNumber)
{
    unsigned long long x = 0;
    x = x | a;
    x = x << 8;
    x = x | b;
    x = x << 8;
    x = x | c;
    x = x << 32;
    x = x | someNumber;
    return x;
}

myStruct * decompress(unsigned long long x)
{
    printBinary(x);
    myStruct * m = new myStruct();
    m->someNumber = x | 4294967296;
    x = x >> 32;
    m->c = x | 256;
    x = x >> 8;
    m->b = x | 256;
    x = x >> 8;
    m->a = x | 256;
    return m;
}