是否有一种定义明确且性能良好的方法将 double 按位转换为 uint64_t 并返回

Is there a well-defined and performant way to bitwise convert double to uint64_t and back

之前没有回答我问题的类似问题:

我需要将 double 保存到 STM32L476 微控制器上的闪存中。闪存控制器以 64 位块工作,来自 ST 的 HAL API 为要写入的数据采用 uint64_t 参数。为此,我需要将 double 变量中的位转换为一个或多个 uint64_ts.

我尝试了以下,这是 UB:

uint64_t flash_write_val = *(uint64_t*)&double_value;

但是,我收到有关违反严格别名规则的编译器警告。如果不调用 UB,我将如何执行此操作?它不需要超级便携。它只能在 Cortex M4F 内核上有效。

我在考虑这个:

union uint64_double {
    uint64_t flash_friendly;
    double math_friendly;
};

这是一个好方法,还是我还在搬起石头砸自己的脚?

只需使用 memcpy 将字节复制到您想要的位置。

memcpy(&flash_write_val, &double_val, sizeof(double_val));

只有Cortex-M3+的答案!!

  1. 指针双关。
uint64_t flash_write_val = *(uint64_t*)&double_value;

由于 Cortex-M3 和更新版本支持非对齐访问,上述内容是 100% 安全的。我个人比较喜欢memcpy的方式,但是在FLASH写函数的时候我一般都是用指针双关

  1. Union punning - 安全便携:
union uint64_double {
    uint64_t flash_friendly;
    double math_friendly;
};
  1. memcpy函数 最可移植且可能最有效的方法,因为现代编译器非常了解 memcpy 的作用,并且在许多情况下内联它。
uint64_t bar(uint64_t *);

uint64_t foo(double double_val)
{
    uint64_t flash_write_val;
    memcpy(&flash_write_val, &double_val, sizeof(flash_write_val));
    return bar(&flash_write_val);
}
foo:
        push    {lr}
        sub     sp, sp, #12
        mov     r2, r0
        mov     r3, r1
        mov     r0, sp
        strd    r2, [sp]
        bl      bar
        add     sp, sp, #12
        ldr     pc, [sp], #4

https://godbolt.org/z/Ws6Yr15x8