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

问题描述 投票:0回答:3

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

位将 uint64_t 转换为 double 并返回到宏中

将 uint64_t 转换为双精度值

我需要将

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

我尝试了以下方法,即UB:

uint64_t flash_write_val = *(uint64_t*)&double_value;

但是,我收到有关违反严格别名规则的编译器警告。在不调用 UB 的情况下我该如何做到这一点?它不需要超级便携。它仅在 Cortex M4F 内核上有效。

我在想这个:

union uint64_double {
    uint64_t flash_friendly;
    double math_friendly;
};

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

c floating-point embedded stm32 cortex-m
3个回答
7
投票

只需使用

memcpy
将字节复制到您想要的位置。

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

0
投票

这是我使用的代码:

template <typename DestT, typename SrcT>
inline constexpr DestT reinterpretType(SrcT src){
    DestT dest;
    memcpy(&dest, &src, sizeof(DestT));
    return dest;
    static_assert(sizeof(DestT) == sizeof(SrcT));
}

如果在类中使用它,请不要忘记将其声明为静态。 奇怪的是,GCC 并没有抱怨 constexpr 表达式中的 memcpy (可能是编译器优化了它)。 注意:没有必要声明第二个类型名:

double d = 1.0d;
uint64_t asUint64 = reinterpretType<uint64_t>(d);
float f = 1.0f;
uint32_t asUint32 = reinterpretType<uint32_t>(f);

-1
投票

这只是 Cortex-M3+ 的答案!!

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

由于 Cortex-M3 及更新版本支持非对齐访问,因此上述内容是 100% 安全的。我个人更喜欢

memcpy
方式,但是在FLASH写入函数中我通常使用指针双关语。

  1. 联合双关语 - 安全且便携:
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

© www.soinside.com 2019 - 2024. All rights reserved.