我想知道如何以明确的方式使用
std::bit_cast
。
因此我需要澄清 cppreference 关于 std::bit_cast 的措辞。 我不明白下面这段话的意思:
对于结果的值表示中不确定的每一位,包含该位的最小对象具有不确定的值;除非该对象是 unsigned char 或 std::byte 类型,否则行为未定义。结果不包含任何不确定的值。
我们来写一个例子:
#include <bit>
#include <cstdint>
struct S9 {
std::uint16_t a : 9;
};
struct S7 {
std::uint8_t a : 7;
};
int main() {
S9 s9;
s9.a = 42;
std::uint16_t a16 = std::bit_cast<std::uint16_t>(s9.a);
// (1) a16 may be uuuuuuu000101010, u being indeterminate bits
S7 s7;
s7.a = 42;
std::uint8_t a8 = std::bit_cast<std::uint8_t>(s7.a);
// (2) a8 may be u0101010, u being indeterminate bits
}
我们所说的对象是什么?
a8
的产生是否被视为定义的行为,而其值是未定义的?a16
的产生是否被视为未定义行为,而其值是未定义的?
标准对位字段有这样的规定 ([class.bit]):
位域在某些机器上从右到左分配,在其他机器上从左到右分配
这意味着从最高有效位 (MSB) 到最低有效位 (LSB) 的顺序在某些系统上可能是从左到右,而在其他系统上可能是从右到左。
换句话说,基本上没有带有位字段的代码是真正可移植的,因为它们的布局(和对齐)是实现定义的。
当你分配时
s9.a = 42;
结果可能是
uuuuuuu000101010
000101010uuuuuuu
,其中 u
表示有点处于不确定状态。或者,如果实现决定对齐方式应为 32 位,则可能是 uuuuuuuuuuuuuuuuuuuuuuu000101010
;位字段的对齐也是实现定义的(意味着它也可以是000101010uuuuuuuuuuuuuuuuuuuuuuu
)
a8 的产生是否被视为已定义行为,而其值是未定义的?
a16 的产生是否被视为未定义行为,而其值是未定义的?
两者均未定义;我将标准的措辞解释为基本上是说,如果结果中的任何位不确定,则
bit_cast
的行为是未定义的* 每个 [bit.cast]:
对于结果的值表示中不确定的每一位,包含该位的最小对象具有不确定的值;行为未定义
*除非在特殊情况下,目标类型是“无符号普通字符类型或
std::byte_t
”