如何在C中制作动态结构

How to make a dynamic structure in C

例如,如果我有这样的结构:

typedef struct __attribute__ ((packed))
{
  uint16_t    ObjectPropertyCode;
  uint16_t    DataType;
  uint8_t     GetSet;
  union
  {
    uint8_t     DefaultValue_u8 ;
    uint16_t    DefaultValue_u16 ;
    uint32_t    DefaultValue_u32 ;
  }DefValue  ;
  uint32_t    GroupCode;
  uint8_t     FormFlag;
}
MTP_ObjectPropDescTypeDef;

我只需要在 DefValue 中有一个元素,具体取决于我的数据类型。 例如,如果我的数据类型是 uint16 ,那么我将像这样发送我的结构:

typedef struct __attribute__ ((packed))
{
  uint16_t    ObjectPropertyCode;
  uint16_t    DataType;
  uint8_t     GetSet;
  uint16_t    DefaultValue_u16 ;
  uint32_t    GroupCode;
  uint8_t     FormFlag;
}
MTP_ObjectPropDescTypeDef;

除非您将数据布局分成多个部分,或者更改数据布局,以便您的可变大小类型位于末尾,否则您的建议无法完成(好吧,无论如何合理)。

有了这个,我们就可以进入不合理的部分了。您可以(ab)使用预处理器在一定程度上有效地实现这一点。 (例如):

#define JOIN3(a, b, c) a##b##c
#define MYSTRUCT(n) \
    struct __attribute__ ((packed)) { \
        uint16_t ObjectPropertyCode; \
        uint16_t DataType; \
        uint8_t GetSet; \
        JOIN3(uint, n, _t) DefaultValue; \
        uint32_t GroupCode; \
        uint8_t FormFlag; \
    }

// ...

{
    MYSTRUCT(8) obj; // uint8_t DefaultValue
    printf("%lu\n", sizeof(obj)); // 11

    MYSTRUCT(16) obj2; // uint16_t DefaultValue
    printf("%lu\n", sizeof(obj2)); // 12

    MYSTRUCT(32) obj3; // uint32_t DefaultValue
    printf("%lu\n", sizeof(obj3)); // 14
}
   

但是,它实现了与仅以三个不同的结构开始的类似效果。考虑在适用的情况下使用替代方法,即将结构分解为多个部分、使用不同的部分或仅使用普通缓冲区。

考虑下面的方法,该方法将根据提供的数据构建缓冲区。例如:

void build_output_buffer(const MTP_ObjectPropDescTypeDef *def, uint8_t *out)
{
    size_t header_size = offsetof(MTP_ObjectPropDescTypeDef, DefValue);
    memcpy(out, def, header_size);
    out += header_size;
    switch (def->DataType) {
        // Copy the appropriate value, e.g.:
        case DataType_U32: { // For demonstration's sake
            memcpy(out, &def->DefValue, 4);
            out += 4;
        } break;
    }
    size_t footer_offset = offsetof(MTP_ObjectPropDescTypeDef, GroupCode);
    size_t footer_size = sizeof(MTP_ObjectPropDescTypeDef) - footer_offset;
    memcpy(out, (uint8_t*)def + footer_offset, footer_size);
}

并确保传入的缓冲区足够大以容纳所有数据。或者在函数内部分配它并 return 它。或者只是跳过缓冲区并使用类似的逻辑将数据发送出去。