C语言 是否有一种定义良好且高性能的方法来按位将double转换为uint64_t并返回

plupiseo  于 2023-11-16  发布在  其他
关注(0)|答案(3)|浏览(117)

以前类似的问题,没有回答我的问题:
bit cast uint64_t to double and back in a macro
Converting uint64_t to Double Value
我需要保存一个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;
};


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

wfsdck30

wfsdck301#

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

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

字符串

zaqlnxep

zaqlnxep2#

以下是我使用的代码:用途:

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

字符串
如果你在类中使用它,不要忘记将它声明为static。奇怪的是,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);

wdebmtf2

wdebmtf23#

这是唯一的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

相关问题