memcpy float 变量到 uint8_t 数组
memcpy float variable into uint8_t array
我正在尝试从 SPI 传输填充的 uint8_t 类型数组中提取一些浮点变量。
然而到目前为止我无法实现正确的提取,所以我写了一个小程序来理解我做错了什么。
首先,我只是用一些浮点数填充缓冲区,并想检查它是否正确完成。我注意到当使用 memcpy 将浮点变量复制到缓冲区并随后打印缓冲区内容时,它仍然包含所有零。但是,当将 float 变量直接分配给 space 时,每个缓冲区位置指向(当前在 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]));
}
}
安全的做法是像复制进去一样复制出来:
float new_float;
memcpy(&new_float, &buffer_rx[sizeof(float)*i], sizeof(float));
printf("buffer_rx[%d] = %f\n", i, new_float);
另一种选择是通过 union
进行类型双关(这在 C 中是允许的,但在 C++ 中是不允许的)这样可以安全地直接访问数组元素而无需 memcpy
ing 它们出。
示例:
#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]);
}
}
要将表示 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
对象所需的方式在内存中定位。
我正在尝试从 SPI 传输填充的 uint8_t 类型数组中提取一些浮点变量。 然而到目前为止我无法实现正确的提取,所以我写了一个小程序来理解我做错了什么。
首先,我只是用一些浮点数填充缓冲区,并想检查它是否正确完成。我注意到当使用 memcpy 将浮点变量复制到缓冲区并随后打印缓冲区内容时,它仍然包含所有零。但是,当将 float 变量直接分配给 space 时,每个缓冲区位置指向(当前在 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]));
}
}
安全的做法是像复制进去一样复制出来:
float new_float;
memcpy(&new_float, &buffer_rx[sizeof(float)*i], sizeof(float));
printf("buffer_rx[%d] = %f\n", i, new_float);
另一种选择是通过 union
进行类型双关(这在 C 中是允许的,但在 C++ 中是不允许的)这样可以安全地直接访问数组元素而无需 memcpy
ing 它们出。
示例:
#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]);
}
}
要将表示 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
对象所需的方式在内存中定位。