windows下C++的反射功能

news2025/1/17 3:52:58

概述

c/c++如果在日志中查看某个结构体/类的每个变量名,变量值信息,只能通过printf逐个格式化,非常繁琐,如何做到类似protobuff转json的序列化功能呢?该dll库先通过分析pdb文件获取结构体/类的变量名称、变量地址,并序列化成完整json字符串,极大降低了开发者工作量。

详细

概述

通过pdb文件查找指定结构体的变量命名和变量地址,将指定的结构体变量内容序列话为json格式。

实现原理

com组件查找pdb文件

使用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;
    }

demo效果:

在release下执行tcdumpTest.exe 看效果

注意:使用前先看‘使用说明.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" });
初始化tcDump,并序列化对象
    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;
序列化结果retJson输出

结果输出

附加接口

能够通过已知结构体大小返回大小一致的结构体名称

 
  1. // 打印pdb中大小为 n的类和结构体名称
  2. std::cout << tcDump_GetSizeClass(sizeof(CTest)) << std::endl;
  3. 输出:---{ CTest }---

工程目录

-tcdump
-tcdumpTest

tcdump为dll工程,核心代码实现。
tcpdumpTest为测试工程。

注意点:

1、本工程基于windows,不支持linux
2、本工程默认支持vs2019,其他版本可以自行编译。
3、使用vs2019编译时,会提示map _Node 错误,只需把xtree文件中对应的 _Node 从protected修改为public,并重新编译即可
4、使用前先看‘使用说明.txt’,需要先注册\DIA SDK\bin\msdia120.dll。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WebGL 从0到1绘制一个立方体

目录 前言 组成立方体的面、三角形、顶点坐标和顶点颜色 通过顶点索引绘制物体 gl.drawElements(mode, count, type, offset) 函数规范 示例程序 彩色立方体&#xff08;HelloCube.js&#xff09; 代码详解 向缓冲区中写入顶点的坐标、颜色与索引 gl.ELEMENT_ARRAY_B…

RFID产线自动化升级改造管理方案

应用背景 在现代制造业中&#xff0c;产线管理是实现高效生产和优质产品的关键环节&#xff0c;产线管理涉及到生产过程的监控、物料管理、工艺控制、质量追溯等多个方面&#xff0c;有效的产线管理可以提高生产效率、降低成本、改善产品质量&#xff0c;并满足市场需求的变化…

elasticsearch1

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…

iText实战--在现有PDF上工作

6.1 使用PdfReader读取PDF 检索文档和页面信息 D:/data/iText/inAction/chapter03/image_direct.pdf Number of pages: 1 Size of page 1: [0.0,0.0,283.0,416.0] Rotation of page 1: 0 Page size with rotation of page 1: Rectangle: 283.0x416.0 (rot: 0 degrees) Is reb…

重新认识架构—不只是软件设计

前言 什么是架构&#xff1f; 通常情况下&#xff0c;人们对架构的认知仅限于在软件工程中的定义&#xff1a;架构主要指软件系统的结构设计&#xff0c;比如常见的SOLID准则、DDD架构。一个良好的软件架构可以帮助团队更有效地进行软件开发&#xff0c;降低维护成本&#xff0…

C# 查找迷宫路径

1.导入图像&#xff0c;并且将图像转灰度 using var img new Image<Bgr, byte>(_path); using var grayImg img.Convert<Gray, byte>(); 2.自动二值化图像 using var inputGrayOut new Image<Gray, byte>(grayImg.Size); // 计算OTSU阈值 var threshol…

【图像处理】VS编译opencv源码,并调用编译生成的库

背景 有些时候我们需要修改opencv相关源码&#xff0c; 这里介绍怎么编译修改并调用修改后的库文件。 步骤 1、下载相关源码工具&#xff1a; 下载opencv4.8源码并解压 https://down.chinaz.com/soft/40730.htm 下载VS2019&#xff0c;社区版免费 https://visualstudio.micro…

【C++】动态规划题目总结(随做随更)

文章目录 一. 斐波那契数列模型1. 第 N 个泰波那契数2. 三步问题3. 使用最小花费爬楼梯解法一&#xff1a;从左往右填表解法二&#xff1a;从右往左填表 一. 斐波那契数列模型 解题步骤&#xff1a; 确定状态表示&#xff08;最重要&#xff09;&#xff1a;明确dp表里的值所…

用Jmeter进行压测详解

简介&#xff1a; 1.概述 一款工具&#xff0c;功能往往是很多的&#xff0c;细枝末节的地方也很多&#xff0c;实际的测试工作中&#xff0c;绝大多数场景会用到的也就是一些核心功能&#xff0c;根本不需要我们事无巨细的去掌握工具的所有功能。所以本文将用带价最小的方式讲…

RocketMQ的介绍和环境搭建

一、介绍 我也不知道是啥&#xff0c;知道有什么用、怎么用就行了&#xff0c;说到mq&#xff08;MessageQueue&#xff09;就是消息队列&#xff0c;队列是先进先出的一种数据结构&#xff0c;但是RocketMQ不一定是这样&#xff0c;简单的理解一下&#xff0c;就是临时存储的…

功率谱密度PSD(笔记)

能量守恒&#xff1a;时域能量等于频域能量 功率谱密度能够反映随机振动的功率关于频率的分布密度 功率谱密度&#xff08;PSD&#xff09;&#xff1a;单位是功率/Hz。针对功率有限信号(能量有限信号用能量谱密度)。表现为是单位频带内信号功率随频率的变换情况&#xff0c;…

【深度学习】Pytorch 系列教程(十一):PyTorch数据结构:3、变量(Variable)介绍

目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量&#xff08;Tensor&#xff09; 2、张量操作&#xff08;Tensor Operations&#xff09; 3、变量&#xff08;Variable&#xff09; 一、前言 ChatGPT&#xff1a; PyTorch是一个开源的机器学习框架&am…

Vulnhub系列靶机---Deathnote: 1死亡笔记

文章目录 信息收集主机发现端口扫描目录扫描dirsearchgobusterdirb扫描 漏洞利用wpscan扫描Hydra爆破 总结 靶机文档&#xff1a;Deathnote: 1 下载地址&#xff1a;Download (Mirror) 难易程度&#xff1a;so Easy 信息收集 主机发现 端口扫描 访问靶机的80端口&#xff0c;报…

什么是 Microsoft Office 365? Excel on Cloud 的好处

什么是Office 365 Office 365 是 Microsoft 的一套程序&#xff0c;可以在本地运行&#xff0c;也可以同步到云存储。 可以从访问程序。 借助 Office 365&#xff0c;您可以在任何地方进行工作&#xff0c;并与世界各地的同事共享工作文档。 Office 365 支持的设备&#xff1a…

涵盖Java核心知识的综合指南:JavaGuide | 开源日报 0912

Snailclimb/JavaGuide Stars: 133.8k License: Apache-2.0 这是一份涵盖大部分 Java 程序员所需要掌握的核心知识库。该项目包含了 Java 基础、集合、IO、并发等方面的内容&#xff0c;并提供了重要知识点详解和源码分析。此外还有计算机基础&#xff08;操作系统、网络&…

题目 1057: 二级C语言-分段函数

有一个函数如下&#xff0c;写一程序&#xff0c;输入x&#xff0c;输出y值。 保留两位小数 样例输入 1 样例输出 1.00 这道题的思路很简单&#xff0c;我直接用if判断输入的X对应的函数Y的区间&#xff0c;代入对应的函数&#xff0c;求出结果。记得变量用浮点型&#xff…

【异常错误】detected dubious ownership in repository ****** is owned by: ‘

今天在github git的时候&#xff0c;突然出现了这种问题&#xff0c;下面的框出的部分一直显示&#xff1a; detected dubious ownership in repository at D:/Pycharm_workspace/SBDD/1/FLAG D:/Pycharm_workspace/SBDD/1/FLAG is owned by: S-1-5-32-544 but the current use…

Arm发布 Neoverse V2 和 E2:下一代 Arm 服务器 CPU 内核

9月14日&#xff0c;Arm发布了新的处理器内核&#xff1a;V2和E2&#xff0c;在官网已经可以看到相关的TRM 手册了。。 四年前&#xff0c;Arm发布了Neoverse系列的CPU设计。Arm决定加大力度进军服务器和边缘计算市场&#xff0c;专门为这些市场设计Arm CPU内核&#xff0c;而…

UART 协议

文章目录 硬件拓扑基本原理起始位数据帧奇偶校验位停止位 参考 硬件拓扑 在 UART 通信中&#xff0c;两个 UART 直接相互通信。发送 UART 将控制设备&#xff08;如 CPU&#xff09;的并行数据转换为串行形式&#xff0c;以串行方式将其发送到接收 UART。只需要两条线即可在两…

elementUI elfrom表单验证无效、不起作用常见原因

今天遇到一个变态的问题&#xff0c;因页面比较复杂&#xff0c;出现几组条件判断&#xff0c;每个template内部又包含很多表单&#xff01;&#xff01; <template v-if"transformTypeValue 1"></template><template v-else-if"transformTypeV…