c++ - 从位域获取完整值

标签 c++ bit-shift bit-fields

我希望创建一个用于我正在构建的体素游戏的 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/

相关文章:

c - 16 位位域导致*从未初始化的内存中读取*警告

c++ - Arcball 相机在 90 度方位角倒转

c++ - 我用宏执行了以下代码

C 64 位左移失败

c - 通过 C 中具有位字段的结构指针访问无符号整数的各个位

c - 在 C 中的位域结构中添加额外的位

c++ - 为什么 C++11 引入了 char16_t 和 char32_t 类型

c++ - 在并发创建线程之前读取修改的变量是否安全?

c - Bit Twiddling - 对该程序的输出感到困惑

java - 在 Python 中获得与 Java 相同的左移