我经常描述现有的结构,我需要任何方法来自动生成结构图......
例如,我的结构很小:
struct SExampleBox
{
int x; //0x0000
int y; //0x0004
float size; //0x0008
}; Size=0x000C
我的想法是将其描述为:(使用宏或者可能是boost.preprocessor)
STRUCT_BEGIN(SExampleBox)
MEMBER(int, x);
MEMBER(int, y);
MEMBER(float size);
STRUCT_END
将其自动展开为:
struct SExampleBox
{
int x;
int y;
float size;
};
void DUMP__SExampleBox(SExampleBox *obj)
{
printf("%p > SExampleObj:\n", obj);
printf(" 0x%04x - int x = %d\n", offsetof(SExampleObj, x), obj->x);
printf(" 0x%04x - int y = %d\n", offsetof(SExampleObj, y), obj->y);
printf(" 0x%04x - float size = %f\n", offsetof(SExampleObj, size), obj->size);
}
调用DUMP__SExampleBox(test);并获得示例输出:
0x00402000 > SExampleObj:
0x0000 - int x = 100
0x0004 - int y = 50
0x0008 - float size = 200.000f
有没有可行的方法呢? 谢谢!
答案 0 :(得分:0)
对值格式化juggle不太满意,但这是可调整的。
语法如下:
DECLARE_STRUCT(SExampleBox,
(int, x)
(int, y)
(float, size)
)
int main(int, char**) {
SExampleBox o{1, 2, 3.14f};
dump(&o);
}
现在,实施。首先,我们需要一个效用函数来为Boost.PP序列添加括号,将(a)(b)
转换为((a))((b))
:
#define glk_pp_detail_doubleSeqParens_0(...)\
((__VA_ARGS__)) glk_pp_detail_doubleSeqParens_1
#define glk_pp_detail_doubleSeqParens_1(...)\
((__VA_ARGS__)) glk_pp_detail_doubleSeqParens_0
#define glk_pp_detail_doubleSeqParens_0_end
#define glk_pp_detail_doubleSeqParens_1_end
#define glk_pp_doubleSeqParens(seq)\
BOOST_PP_CAT(glk_pp_detail_doubleSeqParens_0 seq, _end)
然后我们将构建struct声明的框架和相应的函数:
#define DECLARE_STRUCT(name_, fields_) \
struct name_ { \
BOOST_PP_SEQ_FOR_EACH(DETAIL_DECLARE_FIELD, name_, glk_pp_doubleSeqParens(fields_)) \
}; \
void dump(name_ *obj_) { \
::std::printf("%p > " BOOST_PP_STRINGIZE(name_) ":\n", static_cast<void*>(obj_)); \
BOOST_PP_SEQ_FOR_EACH(DETAIL_PRINT_FIELD, name_, glk_pp_doubleSeqParens(fields_)) \
}
来自glk_pp_doubleSeqParens
的双括号可以将元组序列(type, name)(type, name)
传递给BOOST_PP_SEQ_FOR_EACH
,否则会因为逗号而阻塞它。
现在只需为每个结构成员形成有效的成员声明和打印语句:
#define DETAIL_DECLARE_FIELD(r, structName_, typeAndName_) \
BOOST_PP_TUPLE_ELEM(0, typeAndName_) BOOST_PP_TUPLE_ELEM(1, typeAndName_);
#define DETAIL_PRINT_FIELD_1(structName_, type_, name_) \
::std::printf(" 0x%04zx - " BOOST_PP_STRINGIZE(type_) " " BOOST_PP_STRINGIZE(name_) " = ", offsetof(structName_, name_)); \
::detail_printValue(obj_->name_);
#define DETAIL_PRINT_FIELD(r, structName_, typeAndName_) \
DETAIL_PRINT_FIELD_1(structName_, BOOST_PP_TUPLE_ELEM(0, typeAndName_), BOOST_PP_TUPLE_ELEM(1, typeAndName_))
为每个值选择适当的格式参数有点笨重。我已选择将其推迟到只打印值和换行符的重载集,但您也可以动态构造格式字符串并使用单个printf
。
void detail_printValue(float const &v) { std::printf("%f\n", v); }
void detail_printValue(int const &v) { std::printf("%d\n", v); }