【问题标题】:memcpy float variable into uint8_t arraymemcpy 浮点变量到 uint8_t 数组
【发布时间】:2021-03-04 14:08:19
【问题描述】:

我正在尝试从 SPI 传输填充的 uint8_t 类型的数组中提取一些浮点变量。 但是到目前为止我无法实现正确的提取,所以我编写了一个小程序,以便了解我做错了什么。

首先,我只是用一些浮点数填充了缓冲区,并想检查它是否正确完成。我注意到当使用 memcpy 将浮点变量复制到缓冲区并在之后打印缓冲区内容时,它仍然包含全零。但是,当将 float 变量直接分配给每个缓冲区位置指向的空间(当前在 memcpy 函数下方注释掉的行)时,缓冲区的初始化会按照我想要的方式工作。

谁能指出我的错误。

#include <stdio.h>
#include <string.h>

#define MAX_MSG_LEN 64

static uint8_t buffer_rx[MAX_MSG_LEN];

int main(){
    for(int i=0; i<MAX_MSG_LEN/sizeof(float); i++){
        float myFloat = (float)i;
        printf("myFloat = %f\n", myFloat);
        printf("buffer_rx+sizeof(float)*%d = %p\n", i, (void*)(&buffer_rx[sizeof(float)*i]));
        memcpy(&buffer_rx[sizeof(float)*i], &myFloat, sizeof(float));
        //buffer_rx[sizeof(float)*i] = myFloat;
        printf("buffer_rx[%d] = %f\n", i, (float)(buffer_rx[sizeof(float)*i]));
    }

}

【问题讨论】:

    标签: c pointers type-conversion memcpy


    【解决方案1】:

    要将代表float 的字节移动到字节缓冲区中,只需使用memcpy 复制它们:

    memcpy(&buffer_rx[sizeof(float)*i], &myFloat, sizeof myFloat);
    

    要将缓冲区中的字节复制到代表float 的字节中,只需复制到另一个目录:

    float x;
    memcpy(&x, &buffer_rx[sizeof(float)*i], &myFloat, sizeof x);
    

    不要尝试将缓冲区中的字节直接重新解释为float 或字符类型以外的其他对象。这样做违反了 C (C 2018 6.5 7) 中的别名规则,该规则本质上是说任何对象的内存都只能作为其自己的类型(允许一些微小的变化)或作为字符(字节)访问。因此,float 可以作为字节访问,因为该规则允许将任何内存作为字节访问,但不应将字节数组作为 float 访问。它还可能违反对齐规则,因为字节数组可能不会以float 对象所需的方式定位在内存中。

    【讨论】:

      【解决方案2】:

      这样做的安全方法是将它复制出来,就像你复制它一样:

      float new_float;
      memcpy(&new_float, &buffer_rx[sizeof(float)*i], sizeof(float));
      printf("buffer_rx[%d] = %f\n", i, new_float);
      

      Demo

      另一种选择是通过union(在C 中允许但在C++ 中不允许)进行类型双关语,这样可以安全地直接访问数组元素而无需memcpy 将它们排除在外。

      例子:

      #include <stdio.h>
      #include <string.h>
      #include <stdint.h>
      
      #define MAX_MSG_LEN 64
      
      typedef union {
          uint8_t u8[MAX_MSG_LEN];
          float   f[MAX_MSG_LEN/sizeof(float)];
          double  d[MAX_MSG_LEN/sizeof(double)];
      } buffer_t;
      
      int main(){
          buffer_t sender;
          buffer_t receiver;
      
          // prepare a buffer of floats
          for(int i=0; i<MAX_MSG_LEN/sizeof(float); i++) {
              sender.f[i] = i * 3.14159f;
              printf("%d %f\n", i, sender.f[i]);
          }
      
          // send the buffer somewhere
          memcpy(receiver.u8, sender.u8, MAX_MSG_LEN);
      
          // look at what was received
          for(int i=0; i<MAX_MSG_LEN/sizeof(float); i++) {
              printf("%d %f\n", i, receiver.f[i]);
          }
      }
      

      【讨论】:

      • 谢谢,但是为什么它在使用 buffer_rx[sizeof(float)*i] = myFloat 和打印而不转换为 float* 时会起作用?这是否也意味着这只是打印问题,并且初始化按我想要的方式工作?
      • @Lukas buffer_rx[sizeof(float)*i] = myFloat 分配给单个 uint8_t。其他 3 个字节(如果您的浮点数为 4 个字节)将未分配。所以我不会说它有效。
      • 啊,我明白了,所以当我使用无法仅用 uint8_t 中的 8 位表示的浮点数时,它会失败。
      • @Lukas 是的,确实!
      • @EricPostpischil 好的,我放弃了那部分。 :) 谢谢!在这里,投赞成票:-)
      猜你喜欢
      • 2023-03-16
      • 2023-02-09
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      相关资源
      最近更新 更多