1

您好,我这里有一个 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;
}
4

3 回答 3

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在这个块的开头读到了a,中间没有地方写入任何uint64_ts,所以值必须不变!”

uint64_t这意味着如果您尝试通过uint32_t引用更改对象的值,它将得到错误的答案。由于这非常依赖于哪些优化是可能的和完成的,实际上很容易在测试用例中永远不会遇到问题,但是在你尝试编写的真实程序中看到它——你将永远尝试找到错误,因为您说服自己这不是这个问题。

因此,您确实应该使用位旋转(或内在函数,如果分析表明这是一个性能问题并且有可用的可用)来插入/提取字段,而不是尝试设置一个聪明的结构。

我相信,如果您真的知道自己在做什么,就可以使混叠起作用。但只有在你真的知道自己在做什么的情况下才应该这样做,这包括从内到外了解标准的相关规则(我不知道,所以我不能建议你如何让它发挥作用) . 即使那样,您也可能不应该这样做。

此外,如果您希望您的整数类型具有特定大小,您应该真正使用正确的类型。例如,永远不要使用unsigned int应该正好是 32 位的整数。而是使用uint32_t. 它不仅是自记录的,而且当您尝试在32 位的环境unsigned int中构建程序时,您也不会遇到令人讨厌的意外。

于 2012-06-15T08:44:56.120 回答
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;
}
于 2012-06-15T20:55:50.467 回答
0

使用union. a 的每个元素union占用相同的地址空间。这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现在占用七个字节,最高字节unsigned long long现在没有改变:

f=FF00000004030201
01 02 03 00000004
于 2012-06-15T06:29:23.900 回答