如何将整数数组转换为单个浮点变量?

how to convert array of integers into single float variable?

提问人:Dominykas 提问时间:9/7/2022 更新时间:9/7/2022 访问量:212

问:

我uint8_t数组中存储了 4 个大小的整数:。此数组的长度为 4 个字节 (OD_entry_len = 4),因此等于浮点大小(32 位)。我需要将这个数组转换为浮点变量。对于exampe,我有这些值: 我应该得到 任何想法如何转换它?uint8_t sdo_rx_data_buffer[OD_entry_len];int array[4] = {0xd0, 0x69, 0x83, 0x3f};float i_motor = 1.02666664;

数组 C 浮点 ESP32

评论

0赞 qrsngky 9/7/2022
“int”通常为 4 个字节。应使用uint8_t数组。试试这个:uint8_t array[4] = {0xd0, 0x69, 0x83, 0x3f}; float i_motor = *(float*) array; printf("\n%f\n", i_motor);
3赞 user694733 9/7/2022
@qrsngky 不,不要那样做。具有无效类型的指针类型双关语是严格的别名冲突。它还可能导致可能的对齐问题。请改用。memcpy
0赞 Andreas Wenzel 9/7/2022
在您的问题中,您首先声明数组具有 类型的元素,但后来您编写 ,这意味着这些元素是 类型的。您可能想澄清您的问题。uint8_tint array[4]int
0赞 Andreas Wenzel 9/7/2022
在您的问题中,您使用的是长标识符,例如 和,其描述对读者意义不大。您可能希望通过使这些标识符更短且对读者更有意义来简化您的问题。sdo_rx_data_bufferOD_entry_len

答:

4赞 Lundin 9/7/2022 #1

假设您知道二进制表示在您的系统上给出了一个有效的浮点数,并且您得到了正确的字节数,那么您可以使用:union

#include <stdint.h>
#include <stdio.h>

typedef union
{
  uint8_t raw [sizeof(float)];
  float   f;
} float_converter;

int main (void)
{
  float_converter fc = { .raw = {0xd0, 0x69, 0x83, 0x3f} };
  printf("%f\n", fc.f);
}

x86_64 Linux 上的输出:

1.026667

评论

0赞 chux - Reinstate Monica 9/7/2022
也许是为了实现“浮点i_motor = 1.02666664”?printf("%.8f\n", fc.f);
0赞 Lundin 9/7/2022
@chux-恢复莫妮卡:嗯,那是另一回事了......在这一点上,我们可能还会开始问,这个结果是因为底层具有这种级别的精确度,还是因为隐式提升(“默认参数提升”)需要使用,这实际上是针对类型。floatdouble%fdouble
0赞 chux - Reinstate Monica 9/7/2022
转换为不是问题的一部分。打印 9 位有效数字 () 作为共同是区分所有 .有 9 个不同的输出为 1.026667。打印精度更高有助于证明您的良好方法行之有效。doubleFLT_DECIMAL_DIGfloatfloatfloat"%f"
3赞 Andreas Wenzel 9/7/2022 #2

一种看似有效的错误方法是使用指针重新解释数组。

uint8_t array[4] =  {0xd0, 0x69, 0x83, 0x3f};
float *p = (float*)array;

printf( "%f\n", *p );

但是,此代码具有未定义的行为,因为它违反了严格的别名规则。它还可能存在对齐问题。

在编译器 gcc 和 clang 上,您可以在指针上使用 __attribute__((__may_alias__)) ,这样就不会出现严格的别名冲突:p

uint8_t array[4] =  {0xd0, 0x69, 0x83, 0x3f};
float __attribute__((__may_alias__)) *p = (float*)array;

printf( "%f\n", *p );

但是,仍可能存在对齐问题。

另一种完全符合 ISO C 标准(因此应该适用于所有编译器)的方法是使用 memcpy

uint8_t array[4] =  {0xd0, 0x69, 0x83, 0x3f};
float f;

memcpy( &f, array, sizeof f );

printf( "%f\n", f );

大多数编译器会在编译器优化处于活动状态时进行优化。memcpy

不过,要注意字节序问题。发布的代码仅适用于 little-endian 平台。

评论

2赞 Lundin 9/7/2022
“但是,这具有未定义的行为,因为它违反了严格的锯齿规则,并且还可能存在对齐问题。”那么为什么要提到它,因为它总是错的呢?
1赞 Andreas Wenzel 9/7/2022
@Lundin:我提到它是为了解释为什么应该改用它。此外,与此同时,我在回答中添加了在 gcc 和 clang 上使用的可能性。memcpy__attribute__((__may_alias__))
1赞 Lundin 9/7/2022
然而,严格别名是一种普通的损坏语言功能,因此最好首先使用 ,我认为它仅适用于 gcc 而不是 clang(gcc 历史上是这方面最破碎的编译器)。此外,无缘无故地将非标准的 gcc 扩展拖入代码中简直是不好的做法。在我看来,你的 memcpy 示例很好,根本不需要答案的第一部分。-fno-strict-aliasing
2赞 romkey 9/7/2022
@Lundin,像这样包含“接近但不完全”的答案有很多价值,我很高兴它们是这个答案的一部分。这些答案和对为什么它们不是好解决方案的解释对于教导那些可能认为它们是好解决方案的人非常有帮助。
1赞 romkey 9/8/2022
@chux-恢复莫妮卡,好吧,我强烈不同意你的看法。答案清楚地表明,这些都不是好的解决方案,并明确了原因。受教的时刻。