此代码可与 GCC 配合使用,优化程度低于
-O2
或在 clang 中。
constexpr uint16_t KEY_BITS = 70;
constexpr unsigned __int128 KEY_BITS_MASK = (((unsigned __int128) 1) << KEY_BITS) - 1;
struct Entry
{
unsigned __int128 left : 4;
unsigned __int128 right : 4;
unsigned __int128 key : KEY_BITS;
};
Entry data;
void print(unsigned __int128 a)
{
std::cerr << std::bitset<16>(a >> 64) << std::bitset<64>(a) << std::endl;
}
void store(unsigned __int128 key, uint8_t left, uint8_t right)
{
data.left = left;
data.right = right;
data.key = key & KEY_BITS_MASK;
print(key & KEY_BITS_MASK);
print(data.key);
assert(data.key == (key & KEY_BITS_MASK));
}
在带有
-O2
的 GCC 中,它似乎是未定义的,因为添加或删除打印会改变行为。在“坏”情况下,它首先将 &
运算的结果转换为 64 位整数。
这是一个错误还是我误解了这些类型的行为方式。看起来不应该是未定义的。
位域的实现方式是“实现定义的”,而不是 C++ 标准的一部分。这意味着位域可以用额外的位填充,以在内存中对齐它们。这意味着它们不能安全地用于存储实际位。它们仅确保设置和读取的结果的行为就像变量具有指定的位数。
似乎 cppreference bit_field 也包含该信息(查看注释部分)