将 std::uint64_t 编码为浮点数向量

Encode a std::uint64_t into vector of floats

提问人:Foaly 提问时间:11/9/2023 最后编辑:genpfaultFoaly 更新时间:11/9/2023 访问量:91

问:

我必须做一些肮脏的诡计并传递一个应用程序。不幸的是,我只能为此使用 a。std::uint64_tstd::vector<float>

据我了解,大多数平台上都是 32 位,因此应该可以将 64 位拆分为两个 32 位整数,将它们表示为将它们放在向量中并在另一端反转该过程。floatstd::uint64_tfloat

我该怎么做?

C++ 转换 位操作

评论


答:

5赞 Homer512 11/9/2023 #1

快速而肮脏,但如果我没记错的话,符合标准:

#include <cassert>
// using assert
#include <cstdint>
// using std::uint64_t
#include <cstring>
// using std::memcpy
#include <vector>

std::vector<float> pack(std::uint64_t value)
{
    static_assert(sizeof(value) >= sizeof(float));
    static_assert(sizeof(value) % sizeof(float) == 0);
    std::vector<float> rtrn(sizeof(value) / sizeof(float));
    std::memcpy(rtrn.data(), &value, sizeof(value));
    return rtrn;
}
std::uint64_t unpack(const std::vector<float>& packed)
{
    std::uint64_t rtrn;
    assert(packed.size() == sizeof(rtrn) / sizeof(float));
    std::memcpy(&rtrn, packed.data(), sizeof(rtrn));
    return rtrn;
}

评论

0赞 Foaly 11/9/2023
太棒了,非常感谢!
5赞 Red.Wave 11/9/2023 #2

C++23:

#include <bit>
#include <array>
#include <ranges>
#include <vector>

std::unint64_t ui64{whatever()};
auto vec = std::bit_cast< std::array<float, 2> >(ui64)
         | std::ranges::to<std::vector>();

bit_cast需要 C++20 和 C++23。您也可以使用传统的构造函数从数组中隐蔽,但可读性更强,更不容易出现错别字。ranges::tovector::vector(begin, end)ranges::to

往复式例程

std::vector<float> const flt_vec = {float1(), float2()};
std::array<float,2> flt_arr{};
for(auto&& [a,v] : std::views::zip(flt_arr, vec_arr))
    a=v;
auto ui64 = std::bit_cast<std::uint64_t>(flt_arr);

在尝试任何这些方法之前,您可以检查大小是否匹配,或者应该使用另一种介质类型:floatuint64_tbit_cast

static_assert(sizeof(std::uint64_t)==sizeof(std::array<float, 2>));

在 C++20 之前,是 C++ 中唯一可靠的类型双关方法;但此函数具有众所周知的缺陷,不妨碍在用户代码中使用它。为了所有相关的 UB,它也不能在编译时计算的上下文中使用。因此,C++20 引入了一种可靠的编译器魔法,用于对琐碎的类型进行类型化。如果源和目标相等,则此函数返回与源对象具有完全相同的位模式的目标类型的值。std::memcpystd::bit_castconstexprsizeof

评论

1赞 Foaly 11/9/2023
感谢您向我展示 C++23 方法!不幸的是,我们使用的编译器仍在 C++17 上......但我会记住它,以备将来:)