Home > other >  How is it possible to safely copy an int into a byte array unaligned?
How is it possible to safely copy an int into a byte array unaligned?

Time:11-28

I created a byte array, uint8_t data[256], and I would like to read and write data to it at arbitrary positions. The position offset could be any number, so it could result in an unaligned access. For example if sizeof(int32_t) == 4 then position % sizeof(int32_t) != 0

It works now but, as far as I know, some platforms do not directly support unaligned access. I would like to make it work in that case as well.

#include <cstdint>
#include <iostream>

void write(uint8_t* data, uint32_t position, int32_t value) {
    int32_t* ptr = reinterpret_cast<int32_t*>(&data[position]);
    
    *ptr = value;
}

int32_t read(uint8_t* data, uint32_t position) {
    int32_t* ptr = reinterpret_cast<int32_t*>(&data[position]);
    
    return *ptr;
}

int main()
{
    uint8_t data[256];
    int32_t value = 123456789;
    uint32_t position = 1; // Example for unaligned access

    write(data, position, value);
    
    int32_t read_value = read(data, position);
    
    std::cout << read_value << std::endl;

    return 0;
}

I prefer to use the standard library, if there is a solution there for this problem.

CodePudding user response:

I see no placement new in your code, making both reinterpret_casts undefined behaviour. The returned pointer can only be dereferenced if at the given address exists an object of the specified type. With exception of char, std::byte, unsigned char which can always be dereferenced.

The safe way how to serialize and deserialize objects is through std::memcpy:

void write(unsigned char* data, uint32_t position, int32_t value) {
   
    std::memcpy(data position,&value,sizeof(value));
}

int32_t read(unsigned char* data, uint32_t position) { 
    int32_t result;
    std::memcpy(&result,data position,sizeof(result));
    return result;
}

This also solves any aligment issues.

CodePudding user response:

To avoid possible issues of violating strict aliasing rules, you can use the std::memcpy function:

#include <cstring> // For std::memcpy

void write(uint8_t* data, uint32_t position, int32_t value)
{
    std::memcpy(&data[position], &value, sizeof(value));
}

int32_t read(uint8_t* data, uint32_t position)
{
    int answer;
    std::memcpy(&answer, &data[position], sizeof(answer));
    return answer;
}

From the (second) linked cppreference page:

Where strict aliasing prohibits examining the same memory as values of two different types, std::memcpy may be used to convert the values.

  • Related