以前的类似问题没有回答我的问题:
我需要将
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;
};
这是一个好方法,还是我还在搬起石头砸自己的脚?
只需使用
memcpy
将字节复制到您想要的位置。
memcpy(&flash_write_val, &double_val, sizeof(double_val));
这是我使用的代码:
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);
这只是 Cortex-M3+ 的答案!!
uint64_t flash_write_val = *(uint64_t*)&double_value;
由于 Cortex-M3 及更新版本支持非对齐访问,因此上述内容是 100% 安全的。我个人更喜欢
memcpy
方式,但是在FLASH写入函数中我通常使用指针双关语。
union uint64_double {
uint64_t flash_friendly;
double math_friendly;
};
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