[英]std::bit_cast with std::array
In his recent talk “Type punning in modern C++” Timur Doumler said that std::bit_cast
cannot be used to bit cast a float
into an unsigned char[4]
because C-style arrays cannot be returned from a function.在他最近的演讲“现代 C++ 中的类型双关语”中, Timur Doumler说std::bit_cast
不能用于将float
位转换为unsigned char[4]
,因为不能从 function 返回 C 样式的 arrays。 We should either use std::memcpy
or wait until C++23 (or later) when something like reinterpret_cast<unsigned char*>(&f)[i]
will become well defined.我们应该使用std::memcpy
或等到 C++23(或更高版本),当reinterpret_cast<unsigned char*>(&f)[i]
类的东西将变得明确时。
In C++20, can we use an std::array
with std::bit_cast
,在 C++20 中,我们可以将std::array
与std::bit_cast
一起使用吗?
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
instead of a C-style array to get bytes of a float
?而不是 C 样式的数组来获取float
的字节?
Yes, this works on all major compilers, and as far as I can tell from looking at the standard, it is portable and guaranteed to work.是的,这适用于所有主要的编译器,据我看标准,它是可移植的并且保证可以工作。
First of all, std::array<unsigned char, sizeof(float)>
is guaranteed to be an aggregate ( https://eel.is/c++draft/array#overview-2 ).首先, std::array<unsigned char, sizeof(float)>
保证是一个聚合( https://eel.is/c++draft/array#overview-2 )。 From this follows that it holds exactly a sizeof(float)
number of char
s inside (typically as a char[]
, although afaics the standard doesn't mandate this particular implementation - but it does say the elements must be contiguous) and cannot have any additional non-static members.由此得出,它在内部精确地保存了sizeof(float)
数量的char
(通常作为char[]
,尽管 afaics 标准没有强制要求这种特定的实现 - 但它确实说元素必须是连续的)并且不能有任何其他非静态成员。
It is therefore trivially copyable, and its size matches that of float
as well.因此它很容易复制,并且它的大小也与float
相匹配。
Those two properties allow you to bit_cast
between them.这两个属性允许您在它们之间进行bit_cast
。
Per [array]/1-3 :每个[array]/1-3 :
The header
<array>
defines a class template for storing fixed-size sequences of objects. header<array>
定义了一个 class 模板,用于存储固定大小的对象序列。 An array is a contiguous container.数组是一个连续的容器。 An instance ofarray<T, N>
storesN
elements of typeT
, so thatsize() == N
is an invariant.array<T, N>
的实例存储了N
个T
类型的元素,因此size() == N
是一个不变量。An array is an aggregate that can be list-initialized with up to
N
elements whose types are convertible toT
.数组是一个聚合,可以使用最多N
个元素进行列表初始化,这些元素的类型可以转换为T
。An array meets all of the requirements of a container and of a reversible container (
[container.requirements]
), except that a default constructed array object is not empty and that swap does not have constant complexity.数组满足容器和可逆容器 ([container.requirements]
) 的所有要求,除了默认构造的数组 object 不是空的并且交换没有恒定的复杂性。 An array meets some of the requirements of a sequence container.数组满足序列容器的一些要求。 Descriptions are provided here only for operations on array that are not described in one of these tables and for operations where there is additional semantic information.此处仅针对这些表之一中未描述的数组操作以及存在附加语义信息的操作提供描述。
The standard does not actually require std::array
to have exactly one public data member of type T[N]
, so in theory it is possible that sizeof(To) != sizeof(From)
or is_trivially_copyable_v<To>
.该标准实际上并不要求std::array
恰好有一个T[N]
类型的公共数据成员,因此理论上sizeof(To) != sizeof(From)
或is_trivially_copyable_v<To>
是可能的。
I will be surprised if this doesn't work in practice, though.不过,如果这在实践中不起作用,我会感到惊讶。
Yes.是的。
According to the paper that describes the behaviour of std::bit_cast
, and its proposed implementation as far as both types have the same size and are trivially copyable the cast should be successful.根据描述std::bit_cast
行为的论文及其建议的实现,只要两种类型具有相同的大小并且可以轻松复制,强制转换应该是成功的。
A simplified implementation of std::bit_cast
should be something like: std::bit_cast
的简化实现应该类似于:
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
static_assert(sizeof(Dest) == sizeof(Source));
static_assert(std::is_trivially_copyable<Dest>::value);
static_assert(std::is_trivially_copyable<Source>::value);
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
Since a float (4 bytes) and an array of unsigned char
with size_of(float)
respect all those asserts, the underlying std::memcpy
will be carried out.由于浮点数(4 字节)和带有size_of(float)
的unsigned char
数组尊重所有这些断言,因此将执行底层std::memcpy
。 Therefore, each element in the resulting array will be one consecutive byte of the float.因此,结果数组中的每个元素都将是浮点数的一个连续字节。
In order to prove this behaviour, I wrote a small example in Compiler Explorer that you can try here: https://godbolt.org/z/4G21zS .为了证明这种行为,我在 Compiler Explorer 中编写了一个小示例,您可以在此处尝试: https://godbolt.org/z/4G21zS 。 The float 5.0 is properly stored as an array of bytes ( Ox40a00000
) that corresponds to the hexadecimal representation of that float number in Big Endian .浮点数 5.0 正确存储为字节数组 ( Ox40a00000
),对应于Big Endian中该浮点数的十六进制表示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.