例如,如果我有这样的结构:
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;
根据我的DataType,我只需要在DefValue中有一个元素。例如,如果我的DataType是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("%lun", sizeof(obj)); // 11
MYSTRUCT(16) obj2; // uint16_t DefaultValue
printf("%lun", sizeof(obj2)); // 12
MYSTRUCT(32) obj3; // uint32_t DefaultValue
printf("%lun", 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);
}
并确保传入的缓冲区足够大,可以容纳所有数据。或者在函数内部分配并返回。或者跳过缓冲区,用类似的逻辑发送数据。