我有一个用作句柄的 64 位整数。必须将 64 位分成以下字段,以便单独访问:
size : 30 bits
offset : 30 bits
invalid flag : 1 bit
immutable flag : 1 bit
type flag : 1 bit
mapped flag : 1 bit
我能想到的两种方法是:
1) 传统的位操作(& | << >>
)等。但我觉得这有点神秘。
2) 使用位域结构:
#pragma pack(push, 1)
struct Handle {
uint32_t size : 30;
uint32_t offset : 30;
uint8_t invalid : 1;
uint8_t immutable : 1;
uint8_t type : 1;
uint8_t mapped : 1;
};
#pragma pack(pop)
然后访问一个字段就变得很清楚了:
handle.invalid = 1;
但我知道位域存在很多问题且不可移植。
我正在寻找实现此位操作的方法,目的是最大限度地提高代码的清晰度和可读性。我应该采用哪种方法?
旁注:
句柄大小不得超过64位;
只要遵守每个字段的大小,这些字段在内存中的顺序无关紧要;
句柄不会保存/加载到文件中,因此我不必担心字节顺序问题。
最佳答案
我会选择位域解决方案。
只有当您想以二进制形式存储并稍后使用不同的编译器或更常见的不同机器体系结构读取位域时,位域才是“不可移植的”。这主要是因为标准没有定义字段顺序。
在您的应用程序中使用位域就可以了,只要您没有“二进制可移植性”的要求(将您的 Handle
存储在一个文件中并在不同的系统上使用由编译的代码读取它不同的编译器或不同的处理器类型),它会工作得很好。
显然,您需要做一些检查,例如sizeof(Handle) == 8
应该在某个地方完成,以确保您获得正确的大小,并且编译器尚未决定将您的两个 30 位值放在单独的 32 位字中。为了提高在多种架构上成功的机会,我可能会将类型定义为:
struct Handle {
uint64_t size : 30;
uint64_t offset : 30;
uint64_t invalid : 1;
uint64_t immutable : 1;
uint64_t type : 1;
uint64_t mapped : 1;
};
有一些规则是编译器不应该“拆分元素”,如果您将某些东西定义为 uint32_t,并且字段中只剩下两位,则整个 30 位移动到下一个 32 位元素。 [它可能适用于大多数编译器,但以防万一,始终使用相同的 64 位类型是更好的选择]
关于c++ - 64 位整数句柄类型的简明位操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24582834/