原始数据类型的通用存储

时间:2019-05-15 14:56:43

标签: c pointers

存储是一部分内存:

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语言中的标准做法吗? 是否假设我在存储其他数据类型时应该将内存存入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 :(得分:0)

  

这是C语言中的标准做法吗?是否以为我应该忘了   存储其他数据类型时,将其放入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情况更可能生成最佳代码。