我希望创建一个用于我正在构建的体素游戏的 block 结构(仅背景上下文),但是我在保存和加载时遇到了问题。
我可以将一个 block 表示为单个 Uint16 并移位位以获得不同的元素,例如 block ID 和运行状况,或者我可以使用如下所示的位字段:
struct Block
{
Uint16 id : 8;
Uint16 health : 6;
Uint16 visible : 1;
Uint16 structural : 1;
}
使用第一种方法,当我希望保存 block 数据时,我可以简单地将 Uint16 的值转换为十六进制值并将其写入文件。通过加载,我可以简单地读取数字并将其转换回来,然后返回到通过手动位移位读取各个位。
我的问题是,我无法弄清楚如何获取我使用位域方法使用的 Uint16 的整个值,这意味着我无法将 block 数据保存为单个十六进制值。
所以,问题是如何获取存储在由不同位字段组成的 block 结构中的实际单个 Uint16。如果不可能,那也没关系,因为我已经说过我的手动位移方法工作得很好。我只是想分析一下哪种存储和修改数据的方法确实更快。
如果我错过了一个关键细节,或者您需要任何额外的信息来帮助我,请务必询问。
最佳答案
union 可能是最干净的方式:
#include <iostream>
typedef unsigned short Uint16;
struct S {
Uint16 id : 8;
Uint16 health : 6;
Uint16 visible : 1;
Uint16 structural : 1;
};
union U {
Uint16 asInt;
S asStruct;
};
int main() {
U u;
u.asStruct.id = 0xAB;
u.asStruct.health = 0xF;
u.asStruct.visible = 1;
u.asStruct.structural = 1;
std::cout << std::hex << u.asInt << std::endl;
}
这会打印出cfab
。
更新:
经过进一步考虑和更深入地阅读后,我决定任何类型的双关语都是不好的。相反,我建议硬着头皮并明确地进行一些调整来构造序列化的值:
#include <iostream>
typedef unsigned short Uint16;
struct Block
{
Uint16 id : 8;
Uint16 health : 6;
Uint16 visible : 1;
Uint16 structural : 1;
operator Uint16() {
return structural | visible << 2 | health << 4 | id << 8;
}
};
int main() {
Block b{0xAB, 0xF, 1, 1};
std::cout << std::hex << Uint16(b) << std::endl;
}
这还有一个额外的好处,那就是它会打印与初始化程序顺序匹配的 abf5
。
如果您担心性能,您可以使用编译器优化掉的函数,而不是使用 operator
成员函数:
...
constexpr Uint16 serialize(const Block& b) {
return b.structural | b.visible << 2 | b.health << 4 | b.id << 8;
}
int main() {
Block b{0xAB, 0xF, 1, 1};
std::cout << std::hex << serialize(b) << std::endl;
}
最后,如果速度比内存更重要,我建议去掉位字段:
struct Block
{
Uint16 id;
Uint16 health;
Uint16 visible;
Uint16 structural;
};
关于c++ - 从位域获取完整值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28786590/