你好我这里有一个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;
}
答案 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)
使用union
。 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
现在占用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;
}