Общее хранилище примитивных типов данных - PullRequest
0 голосов
/ 15 мая 2019

Память - это часть памяти:

U08* storage; 

Текущая реализация допускает только чтение / запись данных U32.

U32 read(void* storage_somewhere) {
    return *(U32*)storage_somewhere;
}

void write(void* storage_somewhere, U32 data_u32) {
    *(U32*)storage_somewhere = data_u32;
}

Это стандартная практика в C?Предполагается ли, что я должен использовать memcpy в U32 при хранении других типов данных?

Учитывая, что мне нужно:

  • Чтение / запись значений 1/2/4байты, со знаком / без знака / с плавающей запятой

  • Переносимый код (требуется для запуска в какой-либо встроенной системе)

Насколько я понимаю, реализация чего-то вроде:

void read(void* storage_somewhere, void* data_ptr, DATA_TYPE data_type)
void write(void* storage_somewhere,void* data_ptr, DATA_TYPE data_type)

с определенным приведением указателей на основе data_type:

switch(data_type)
...
   case tF32:
       *(F32*)storage_somewhere = val_f32
...

приведет к неопределенному поведению.

Какой рекомендуемый подход?Я предполагаю, что вместо этого следует использовать memcpy - но это означает, что я мог бы просто сохранить существующие функциональные возможности.

1 Ответ

0 голосов
/ 15 мая 2019

Это стандартная практика в Си? Предполагается, что я должен memcpy в U32 при хранении других типов данных?

Это зависит от того, что вы подразумеваете под "этим". Преобразование указателей объектов назад и вперед между типами void * и другими типами указателей объектов является довольно распространенным явлением, и оно служит разумным целям (а иногда и необоснованным). С другой стороны, совсем не типично поддерживать постоянный пул памяти, в который вы записываете и читаете значения различного типа.

Но если вы хотите что-то, что служит плоским пулом примитивов, то объединение массивов, вероятно, будет лучшим выбором:

#define WORD_COUNT 1024

union {
    int8_t   as_schars[WORD_COUNT * 4];
    uint8_t  as_uchars[WORD_COUNT * 4];
    int16_t  as_sshorts[WORD_COUNT * 2];
    uint16_t as_ushorts[WORD_COUNT * 2];
    int32_t  as_sints[WORD_COUNT];
    uint32_t as_uints[WORD_COUNT];
    float    as_floats[WORD_COUNT];  // assumes 32-bit floats
} primitives;

Затем вы можете обращаться к элементам напрямую, без вызовов функций, с помощью выражений, таких как

uint8_t a_byte = primitives.as_uchars[42];
int16_t a_short = primitives.as_sshorts[222];
float f = primitives.as_floats[665];

primitives.as_uints[1] = 12;

У вас также нет риска неопределенного поведения, возникающего при наведении указателей вперед и назад и разыменовании результатов.


В качестве альтернативы, если ваше хранилище разделено на 32-разрядные блоки, у вас есть пара других основанных на объединении альтернатив, основанных на объединении для отдельных модулей, таких как:

union primitive {
    int8_t   as_schar;
    uint8_t  as_uchar;
    int16_t  as_sshort;
    uint16_t as_ushort;
    int32_t  as_sint;
    uint32_t as_uint;
    float    as_float;  // assumes 32-bit floats
};
  • При условии, что вы можете гарантировать, что у такого объединения нет отступов, вы можете использовать его в качестве базового типа для хранения и обмена данными:

    union primitive prim = /* ... */;
    
    uint8_t a_byte = prim.as_uchar;
    int16_t a_short = prim.as_sshort;
    float f = prim.as_float;
    
  • Если вы не можете предположить или гарантировать, что такое объединение имеет правильный размер хранилища, то, вероятно, все же лучше использовать его для хранения и восстановления данных, чем использовать memcpy:

    int16_t read_s16(uint32_t *storage_somewhere) {
        return ((union primitive) { .as_uint = *storage_somewhere }).as_sshort;
    }
    
    void write_float(uint32_t *storage_somewhere, float data) {
        *storage_somewhere = ((union primitive) { .as_float = data }).as_uint;
    }
    

Эти альтернативы дают компилятору как можно более ясное представление о том, что вы делаете, и с большей вероятностью он сгенерирует оптимальный код для этого, чем для случая memcpy.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...