这一篇内容我们来解答复杂参数定义过程中提出的疑问,本文有大量的模板和宏展开,请耐心阅读。
1、不含灵活数组的复杂结构体定义
DEFINE_AND_DESCRIBE_C2STRUCT和C2FIELD是不能分开的,使用时必须要按顺序依次调用这两个宏定义。宏定义比较复杂,我们以C2StoreIonUsageStruct为例直接看展开后的样子。
将DEFINE_AND_DESCRIBE_C2STRUCT(StoreIonUsage)展开变成:
public:
enum : uint32_t { CORE_INDEX = kParamIndexStoreIonUsage };
private:
const static std::vector<C2FieldDescriptor> _FIELD_LIST__unused; /**< structure fields */
public:
typedef C2StoreIonUsageStruct _type; /**< type name shorthand */
static const std::vector<C2FieldDescriptor> FieldList(); /**< structure fields factory */
} C2_PACK;
const std::vector<C2FieldDescriptor> C2StoreIonUsageStruct::FieldList() { return _FIELD_LIST; }
const std::vector<C2FieldDescriptor> C2StoreIonUsageStruct::_FIELD_LIST = {
将所有的C2FIELD展开变成:
C2FieldDescriptor(&((_type*)(nullptr))->usage, "usage"),
C2FieldDescriptor(&((_type*)(nullptr))->capacity, "capacity"),
C2FieldDescriptor(&((_type*)(nullptr))->heapMask, "heap-mask"),
C2FieldDescriptor(&((_type*)(nullptr))->allocFlags, "alloc-flags"),
C2FieldDescriptor(&((_type*)(nullptr))->minAlignment, "min-alignment"),
将所有的内容拼接起来得到完整的结构体定义:
struct C2StoreIonUsageStruct {
inline C2StoreIonUsageStruct() {
memset(this, 0, sizeof(*this));
}
inline C2StoreIonUsageStruct(uint64_t usage_, uint32_t capacity_)
: usage(usage_), capacity(capacity_), heapMask(0), allocFlags(0), minAlignment(0) { }
uint64_t usage; ///< C2MemoryUsage
uint32_t capacity; ///< capacity
int32_t heapMask; ///< ion heapMask
int32_t allocFlags; ///< ion allocation flags
uint32_t minAlignment; ///< minimum alignment
public:
enum : uint32_t { CORE_INDEX = kParamIndexStoreIonUsage };
private:
const static std::vector<C2FieldDescriptor> _FIELD_LIST __unused; /**< structure fields */
public:
typedef C2StoreIonUsageStruct _type; /**< type name shorthand */
static const std::vector<C2FieldDescriptor> FieldList(); /**< structure fields factory */
} C2_PACK;
const std::vector<C2FieldDescriptor> C2StoreIonUsageStruct::FieldList() { return _FIELD_LIST; }
const std::vector<C2FieldDescriptor> C2StoreIonUsageStruct::_FIELD_LIST = {
C2FieldDescriptor(&((_type*)(nullptr))->usage, "usage"),
C2FieldDescriptor(&((_type*)(nullptr))->capacity, "capacity"),
C2FieldDescriptor(&((_type*)(nullptr))->heapMask, "heap-mask"),
C2FieldDescriptor(&((_type*)(nullptr))->allocFlags, "alloc-flags"),
C2FieldDescriptor(&((_type*)(nullptr))->minAlignment, "min-alignment"),
};
好家伙,难道这就是宏魔法吗?!
DEFINE_AND_DESCRIBE_C2STRUCT定义在C2Param.h中,它的作用是给结构体定义一个匹配的CORE_INDEX,并且开始描述结构体的字段,该宏必须要在结构体定义的最后面使用。
从展开后的代码中我们可以看到,它定义了一个枚举常量CORE_INDEX,值为kParamIndexStoreIonUsage。
这里的CORE_INDEX就是上一篇文章中所说的BaseIndex,与结构体相绑定的独一无二的索引。所以在定义复杂结构体时除了结构体本身和对应的字符串外,还要定义一个索引值。索引的命名规则是以kParamIndex为前缀,加上结构体名称中的自定义部分。
索引值的定义参考C2Config.h中的C2ParamIndexKind,里面定义了框架使用的所有结构体索引。如果要自定义索引应该怎么办呢,索引值应该从什么地方开始?在C2Param.h中也有一个枚举,厂商自定义的索引从0x8000开始。
IS_VENDOR_FLAG = 0x00008000,
除了CORE_INDEX外,DEFINE_AND_DESCRIBE_C2STRUCT还提供了描述结构体的方法FieldList,此方法会返回一个C2FieldDescriptor列表,构建C2FieldDescriptor对象需要传入字段相对结构体的偏移量,以及字段名称,具体C2FieldDescriptor是做什么用的,我们会在参数反射一文中做了解。
C2FIELD用于帮助生成C2FieldDescriptor的,它会自动帮助我们计算偏移量,有两点需要注意:
- 填入的参数的顺序需要和结构体字段定义顺序相同;
- 第二个宏参数填入的字段名称可以和结构体成员名称不同。