memcpy 是将 float 打包成 uint32 的标准方法吗?

Is memcpy the standard way to pack float into uint32?

以下是将浮点数的位打包到 uint32 中的最佳方法吗?是的,这可能是一种快速而简单的方法,但我想确保没有更好的方法,或者在进程之间交换值不会引入奇怪的问题。

"Best" 在我的例子中,它永远不会在兼容的 C++ 编译器上中断(给定静态断言),可以在同一台计算机上的两个进程之间打包和解包,并且就像与将 uint32 复制到另一个 uint32 一样快。

进程A:

static_assert(sizeof(float) == sizeof(uint32) && alignof(float) == alignof(uint32), "no");
...

float f = 0.5f;
uint32 buffer[128];

memcpy(buffer + 41, &f, sizeof(uint32)); // packing

进程 B:

uint32 * buffer = thisUint32Is_ReadFromProcessA(); // reads "buffer" from process A
...

memcpy(&f, buffer + 41, sizeof(uint32)); // unpacking

assert(f == 0.5f);

是的,这是进行类型双关的标准方法。 memcpy 上的 Cppreferences 页面甚至包含一个示例,展示了如何使用它将 double 重新解释为 int64_t

#include <iostream>
#include <cstdint>
#include <cstring>

int main()
{
    // simple usage
    char source[] = "once upon a midnight dreary...", dest[4];
    std::memcpy(dest, source, sizeof dest);
    for (char c : dest)
        std::cout << c << '\n';  
    // reinterpreting
    double d = 0.1;
//  std::int64_t n = *reinterpret_cast<std::int64_t*>(&d); // aliasing violation
    std::int64_t n;
    std::memcpy(&n, &d, sizeof d); // OK     
    std::cout << std::hexfloat << d << " is " << std::hex << n
              << " as an std::int64_t\n";
}

ouput

o
n
c
e
0x1.999999999999ap-4 is 3fb999999999999a as an std::int64_t

只要断言通过(您写入和读取的字节数正确),操作就是安全的。你不能把一个64位的对象打包成一个32位的对象,但是你可以把一个32位的对象打包成另一个32位的对象,只要它们是trivially copyable

或者这样:

union TheUnion {
    uint32 theInt;
    float theFloat;
};

TheUnion converter;

converter.theFloat = myFloatValue;
uint32 myIntRep = converter.theInt;

我不知道这是否更好,但这是另一种看待它的方式。