c/c++如果在日志中查看某个结构体/类的每个变量名,变量值信息,只能通过printf逐个格式化,非常繁琐,如何做到类似protobuff转json的序列化功能呢?该dll库先通过分析pdb文件获取结构体/类的变量名称、变量地址,并序列化成完整json字符串,极大降低了开发者工作量。
通过pdb文件查找指定结构体的变量命名和变量地址,将指定的结构体变量内容序列话为json格式。
使用visual studio 编译后的c/c++工程在输出目录都会输出xxx.pdb文件,该pdb文件中包含了工程中类型的符号文件,在软件调试过程中非常重要。pdb文件格式的解析依赖com组件msdia120.dll,在成功注册msdia120.dll组件后,通过提供的方法对pdb文件进行解析:
- HRESULT hr = ::CoInitialize(NULL);
- {
- CComPtr<IDiaDataSource> pDiaDataSource;
- CComPtr<IDiaSession> pDiaSession;
- CComPtr<IDiaSymbol> pGlobalSymbol;
- CComBSTR bstrFilename = pdb_path;
- if (LoadDataFromPdb(bstrFilename, pDiaDataSource, pDiaSession, pGlobalSymbol)) {
- LoadAllUDTs(pGlobalSymbol);//解析所有数据类型,保存在全局变量g_map_udt中
- LoadAllEnums(pGlobalSymbol);
- ret = 1;
- }
- }
- ::CoUninitialize();
- #define TCDUMP(ref_var) \
- tcDump(typeid(ref_var).name(), &(ref_var))
通过输入变量地址,通过关键字typeid获取变量类型,按照不同的变量类型进行不同方式的处理,比如已内置变量类型为列
- if (dump_as_builtin(type, ptr, root)) {
- return true;
- }
- bool dump_inv_as_builtin(const std::string& type, void* ptr, const Json::Value& root)
- {
- static const char* buildin_signed[] = {
- "char",
- "wchar_t",
- "signed char",
- "int",
- "short",
- "long",
- "__int8",
- "__int16",
- "__int32",
- "__int64",
- };
- static const char* buildin_unsigned[] = {
- "unsigned char",
- "unsigned short",
- "unsigned int",
- "unsigned long",
- "unsigned __int8",
- "unsigned __int16",
- "unsigned __int32",
- "unsigned __int64"
- };
- if (type == "bool") {
- *(bool*)ptr = root.asBool();
- return true;
- }
- if (type == "float") {
- *(float*)ptr = root.asFloat();
- return true;
- }
- if (type == "double") {
- *(double*)ptr = root.asDouble();
- return true;
- }
- for (auto t : buildin_signed) {
- if (type == t) {
- switch (type_size(type))
- {
- case 1:
- *(int8_t*)ptr = root.asInt();
- return true;
- case 2:
- *(int16_t*)ptr = root.asInt();
- return true;
- case 4:
- *(int32_t*)ptr = root.asInt();
- return true;
- case 8:
- *(int64_t*)ptr = root.asInt64();
- return true;
- default:
- return false;
- }
- }
- }
- for (auto t : buildin_unsigned) {
- if (type == t) {
- switch (type_size(type))
- {
- case 1:
- *(uint8_t*)ptr = root.asUInt();
- return true;
- case 2:
- *(uint16_t*)ptr = root.asUInt();
- return true;
- case 4:
- *(uint32_t*)ptr = root.asUInt();
- return true;
- case 8:
- *(uint64_t*)ptr = root.asUInt64();
- return true;
- default:
- return false;
- }
- }
- }
- return false;
- }
注意:使用前先看‘使用说明.txt’,需要先注册\DIA SDK\bin\msdia120.dll。
- Class Ctest
- {
- Public:
- Int M_i = 1;
- Float M_f = 0.1;
- Double M_d = 0.2;
- Char M_c = 'a';
- Std::String M_str = "Hello World";
- Std::Vector<Int> M_v;
- Std::Map<Int, Std::String> M_map;
- };
- Ctest Test;
- Test.M_v.Push_back(1);
- Test.M_v.Push_back(2);
- Test.M_v.Push_back(3);
- Test.M_map.Insert({ 1,"hello" });
- test.m_map.insert({ 2,"world" });
- int ret = TCDUMP_INIT(R"(..\tcDumpTest.pdb)");
- if (ret == 0) {
- std::cout << "load pdb failed !!!" << std::endl;
- return 0;
- }
- // 打印 test 变量内容,已json格式输出
- auto retJson = TCDUMP(test);
- if (NULL == retJson) {
- return false;
- }
- std::cout << retJson << std::endl;
能够通过已知结构体大小返回大小一致的结构体名称
// 打印pdb中大小为 n的类和结构体名称
std::cout << tcDump_GetSizeClass(sizeof(CTest)) << std::endl;
输出:---{ CTest }---
-tcdump
-tcdumpTest
tcdump为dll工程,核心代码实现。
tcpdumpTest为测试工程。