Type-pun uint64_t as two uint32_t in C++20(在C++20中键入-pun uint64_t作为两个uint32_t)
问题描述
此代码将auint64_t读取为Twouint32_t是由于严格的别名规则:
uint64_t v;
uint32_t lower = reinterpret_cast<uint32_t*>(&v)[0];
uint32_t upper = reinterpret_cast<uint32_t*>(&v)[1];
同样,写入uint64_t的上半部分和下半部分的代码是UB的,原因相同:
uint64_t v;
uint32_t* lower = reinterpret_cast<uint32_t*>(&v);
uint32_t* upper = reinterpret_cast<uint32_t*>(&v) + 1;
*lower = 1;
*upper = 1;
如何在现代C++20中使用std::bit_cast以安全干净的方式编写此代码?
推荐答案
使用std::bit_cast:
Try it online!
#include <bit>
#include <array>
#include <cstdint>
#include <iostream>
int main() {
uint64_t x = 0x12345678'87654321ULL;
// Convert one u64 -> two u32
auto v = std::bit_cast<std::array<uint32_t, 2>>(x);
std::cout << std::hex << v[0] << " " << v[1] << std::endl;
// Convert two u32 -> one u64
auto y = std::bit_cast<uint64_t>(v);
std::cout << std::hex << y << std::endl;
}
输出:
87654321 12345678
1234567887654321
std::bit_cast仅在C++20中提供,在C++20之前,您可以通过std::memcpy手动实现std::bit_cast,但这种实现与constexpr不同于C++20变体:
template <class To, class From>
inline To bit_cast(From const & src) noexcept {
//return std::bit_cast<To>(src);
static_assert(std::is_trivially_constructible_v<To>,
"Destination type should be trivially constructible");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
对于这种特定的整数情况,最理想的方法是进行位移位/或算术运算,将一个u64转换为两个u32,然后再转换回来。std::bit_cast更通用,支持任何简单的可构造类型,尽管std::bit_cast解决方案应该与现代编译器上的位运算一样优化,具有高优化水平。
与std::bit_cast不同,位运算的一个额外好处是它可以正确地处理字符顺序,它是独立于字符顺序的。
Try it online!
#include <cstdint>
#include <iostream>
int main() {
uint64_t x = 0x12345678'87654321ULL;
// Convert one u64 -> two u32
uint32_t lo = uint32_t(x), hi = uint32_t(x >> 32);
std::cout << std::hex << lo << " " << hi << std::endl;
// Convert two u32 -> one u64
uint64_t y = (uint64_t(hi) << 32) | lo;
std::cout << std::hex << y << std::endl;
}
输出:
87654321 12345678
123456788765432
注意!as@Jarod42points out,位移解不等同于memcpy/bit_cast解,它们的等价性取决于字符顺序。在小端CPUmemcpy/bit_cast上,v[0]中的最低有效位(Lo)为数组元素v[0],最高有效位(Hi)为v[1],而在大端端CPUv[1]上,最低有效位(Lo)为v[1],最高有效位为v[0]。而位移位解决方案与字节顺序无关,在所有系统上,最高有效位(Hi)为uint32_t(num_64 >> 32),最低有效位(Lo)为uint32_t(num_64)。
这篇关于在C++20中键入-pun uint64_t作为两个uint32_t的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:在C++20中键入-pun uint64_t作为两个uint32_t
基础教程推荐
- 为什么派生模板类不能访问基模板类的标识符? 2021-01-01
- 通过引用传递 C++ 迭代器有什么问题? 2022-01-01
- 为什么 RegOpenKeyEx() 在 Vista 64 位上返回错误代码 2021-01-01
- 为什么 typeid.name() 使用 GCC 返回奇怪的字符以及如 2022-09-16
- 如果我为无符号变量分配负值会发生什么? 2022-01-01
- CString 到 char* 2021-01-01
- 非静态 const 成员,不能使用默认赋值运算符 2022-10-09
- 我应该对 C++ 中的成员变量和函数参数使用相同的名称吗? 2021-01-01
- GDB 显示调用堆栈上函数地址的当前编译二进制文 2022-09-05
- 初始化列表*参数*评估顺序 2021-01-01
