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

j2cgzkjk  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(124)

我不得不做一些肮脏的把戏,在应用程序中传递一个std::uint64_t。不幸的是,我只能使用std::vector<float>
据我所知,float在大多数平台上都是32位的,所以应该可以将64位的std::uint64_t拆分为两个32位的int,将它们表示为float,将它们放入向量中,并在另一端反转该过程。
我该怎么做?

628mspwn

628mspwn1#

快速和肮脏,但标准的兼容,如果我没有弄错:

#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;
}

字符串

tct7dpnv

tct7dpnv2#

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需要C20,ranges::to需要C23。你也可以使用传统的vector::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_t的大小是否匹配,或者应该为bit_cast使用另一种介质类型:

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


在C20之前,std::memcpy是C中唯一可靠的类型双关方法;但是这个函数有众所周知的缺陷,不鼓励在用户代码中使用它。为了所有相关的UB,因此C++20引入了std::bit_cast作为constexpr可靠的编译器魔法,用于类型-如果sizeof source和destination相等,则此函数返回与源对象具有完全相同位模式的destination类型的值。

相关问题