std::bit_cast 填充和未定义的行为

问题描述 投票:0回答:1

我想知道如何以明确的方式使用

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
的产生是否被视为未定义行为,而其值是未定义的?

c++ language-lawyer c++20 undefined-behavior bit-cast
1个回答
0
投票

标准对位字段有这样的规定 ([class.bit]):

位域在某些机器上从右到左分配,在其他机器上从左到右分配

这意味着从最高有效位 (MSB) 到最低有效位 (LSB) 的顺序在某些系统上可能是从左到右,而在其他系统上可能是从右到左。

换句话说,基本上没有带有位字段的代码是真正可移植的,因为它们的布局(和对齐)是实现定义的。

当你分配时

s9.a = 42;

结果可能是

uuuuuuu000101010
000101010uuuuuuu
,其中
u
表示有点处于不确定状态。或者,如果实现决定对齐方式应为 32 位,则可能是
uuuuuuuuuuuuuuuuuuuuuuu000101010
;位字段的对齐也是实现定义的(意味着它也可以是
000101010uuuuuuuuuuuuuuuuuuuuuuu


a8 的产生是否被视为已定义行为,而其值是未定义的?

a16 的产生是否被视为未定义行为,而其值是未定义的?

两者均未定义;我将标准的措辞解释为基本上是说,如果结果中的任何位不确定,则

bit_cast
的行为是未定义的* 每个 [bit.cast]:

对于结果的值表示中不确定的每一位,包含该位的最小对象具有不确定的值;行为未定义

*除非在特殊情况下,目标类型是“无符号普通字符类型或

std​::​byte_t

© www.soinside.com 2019 - 2024. All rights reserved.