I am working with a fairly large data structure that needs to be maintained in RAM in two forms: a standard version and an inverted version. Whenever an element is updated, it must be written to the standard memory and bitwise inverted into the second memory. Each read operation must verify both memories to ensure that one value is the bitwise inverse of the other.
The straightforward approach to achieve this involves implementing getter and setter functions for each field. However, to make the implementation more generic, I utilized macros and the offsetof
macro from stddef.h
.
I would appreciate a review to ensure the sanity of this code.
#include
#include
#include
typedef struct __attribute__ ((aligned (4))) double_ram_mem_s
{
uint8_t test_val_u8;
struct inner_struct_s
{
uint8_t test_val_s_u8;
} inner_struct;
} double_ram_mem_t;
double_ram_mem_t double_ram_mem;
double_ram_mem_t double_ram_memi;
bool double_ram_read_u8(uint16_t offset8, uint8_t *value)
{
if (offset8 >= sizeof(double_ram_mem_t))
return false;
uint8_t mem_val = ((uint8_t *)&double_ram_mem)[offset8];
uint8_t memi_val_inv = ~((uint8_t *)&double_ram_memi)[offset8];
if (mem_val != memi_val_inv)
return false;
*value = mem_val;
return true;
}
bool double_ram_write_u8(uint16_t offset8, uint8_t value)
{
if (offset8 >= sizeof(double_ram_mem_t))
return false;
((uint8_t *)&double_ram_mem)[offset8] = value;
((uint8_t *)&double_ram_memi)[offset8] = ~value;
return true;
}
#define DOUBLE_RAM_READ_U8(m_ident, p_value) \
double_ram_read_u8((offsetof(double_ram_mem_t, m_ident)), (p_value))
#define DOUBLE_RAM_WRITE_U8(m_ident, value) \
double_ram_write_u8((offsetof(double_ram_mem_t, m_ident)), (value))
Example how this code could be used:
bool safety_mem_example(void)
{
// init both normal and inversed memories
memset(&double_ram_mem, 0x00, sizeof(double_ram_mem_t));
memset(&double_ram_memi, 0xFF, sizeof(double_ram_mem_t));
// write example
uint8_t write_val = 0xC3;
bool success = DOUBLE_RAM_WRITE_U8(inner_struct.test_val_s_u8, 0xC3);
if (!success)
return success;
// read example
uint8_t read_val;
success = DOUBLE_RAM_READ_U8(inner_struct.test_val_s_u8, &read_val);
if (!success)
return success;
if (read_val != write_val)
return false;
return true;
}
I'm open for completely different approaches and suggestions.