Lukas
Lukas

Reputation: 69

memcpy float variable into uint8_t array

I am trying to extract some float variables out of a array of type uint8_t filled from an SPI transfer. However so far I wasn't able to achieve the correct extraction, so I wrote a small program so understand what I do wrong.

First of all I just filled the buffer with some floats and wanted to check if it's done correctly. I noticed when using memcpy to copy float variables to the buffer and printing the buffers content afterwards it still contains all zeros. However when assigning the float variable directly to the space where each buffer position points (currently commented out line below memcpy function) to the initialization of the buffer works the way I want.

Can somebody point out my mistake please.

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

}

Upvotes: 1

Views: 2905

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117972

The safe way of doing it would be to copy it out just like you copied it in:

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

Demo

Another option could be to do type punning via a union (which is allowed in C but not in C++) which would make it safe to access the array elements directly without memcpying them out.

Example:

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

Upvotes: 1

Eric Postpischil
Eric Postpischil

Reputation: 224311

To move the bytes that represent a float into a buffer of bytes, simply copy them with memcpy:

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

To copy the bytes from a buffer into the bytes that represent a float, simply copy in the other directory:

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

Do not attempt to directly reinterpret the bytes in a buffer as a float or other objects other than character types. Doing so violates the aliasing rule in C (C 2018 6.5 7), which essentially says the memory of any object should only be accessed as its own type (with some allowance for minor variations) or as characters (bytes). So a float can be accessed as bytes because that rule allows accessing any memory as bytes, but an array of bytes should not be accessed as a float. It may also violate a rule about alignment, as an array of bytes may not be positioned in memory in the way required for a float object.

Upvotes: 3

Related Questions