上一篇blog我阐述了一种实现非嵌入式的反射的基本思路。相比于通过宏和模板实现,这种非嵌入的反射的优点是不需要写额外的代码来记录meta信息。

首先,为了在c++中实现反射系统,我认为需要解决以下两个问题:

(1)根据一个给定符号,获取符号对应的地址信息。

(2)根据地址信息,能够对其进行相应操作。

对(2)需要再说明的是:为了能够对地址指向的对象进行操作,需要一些用于描述这个对象的最基本信息(比如对象的类型),而这些信息就是对象的meta信息。有了meta信息,我们才能正确的操作对象。

不同类型的对象的meta信息应该是不同的:

(1)对于简单的数据成员(int、double、struct等),meta信息应该包括数据所占内存的布局。通过内存布局和内存地址,我们可以对其进行get/set操作。

(2)对于函数,meta信息应该有调用惯例(Calling Conventions)、参数、返回值等信息。通过这些信息我们能对函数进行调用操作。

(3)对于类,meta信息可以认为是前两种的组合。应该包含方法表(函数集合)和数据成员集合。

暂时不考虑剩余的其他类型,如模板、宏等。

我以此实现了一个反射系统的demo。基本做法是,通过windows的dia(Debug Interface Access)api读取程序的PDB文件。以此来获得一个符号的地址信息,以及这个符号的基本meta信息。这样可以做到根据一个地址,对数据进行读写的操作。但是对函数来说似乎还不够。为了成功调用函数,我们还需要根据函数的调用惯例,正确的把参数入栈、并从指定位置获取返回值等。libffi就是专门干这事的,但是可惜的是它并不支持msvc:-(

不过好在我熟悉python,知道python也有ctype这个模块来处理ffi(Foreign Function Interface)。把它的源码稍作剪裁应该就可以拿来用了。这部分工作挺顺利的,浏览了一下ctype的实现,发现只需要改非常少的几处即可。cpython的libffi_msvc在此处:D

目前demo功能比较简陋,只实现了对数据对象的get/set,以及调用全局的函数。不过对于其他复杂的对象的反射,基本上参考这两个功能就可以轻松的实现了。

具体的使用如下代码所示:

1、加载程序对应的PDB文件

CReflMgr refl_mgr;//从PDB文件加载反射信息
refl_mgr.LoadDataFromFile(g_wszPdbFileName);

2、对基本数据的get/set

//get instance data member
CReflObject *refl_obj_bar_c;
refl_mgr.GetReflObjectFromParent(refl_obj_bar, L"c", &refl_obj_bar_c);CReflValue refl_val_bar_c;
refl_mgr.GetClassInstDataMember(&bar, refl_obj_bar_c, &refl_val_bar_c);
printf("%d\n", refl_val_bar_c.m_Data.m_I8);//set instance data member
CReflObject *refl_obj_bar_i;
refl_mgr.GetReflObjectFromParent(refl_obj_bar, L"i", &refl_obj_bar_i);CReflValue refl_val_bar_i;
refl_val_bar_i.m_Data.m_I32 = 1024;
refl_mgr.SetClassInstDataMember(&bar, refl_obj_bar_i, &refl_val_bar_i);
printf("%d\n", bar.i);

3、调用函数

//函数
CReflObject *refl_obj_func1;
refl_mgr.GetReflObjectFromGlobal(L"TestCallFunc1", &refl_obj_func1);
refl_mgr.PrintReflObject(refl_obj_func1);std::vector<ffi_obj> vargs;ffi_obj arg1;
arg1.type = ffi_type_sint32;
arg1.value.i32 = 2014;
vargs.push_back(arg1);ffi_obj arg2;
arg2.type = ffi_type_pointer;
arg2.value.p = (void*)"hello world";
vargs.push_back(arg2);ffi_obj ret;
ret.type = ffi_type_void;refl_mgr.CallReflObject(refl_obj_func1, vargs, ret);

当然demo是不完整的,目前我认为还有就几个未解决的比较重要的问题是:

(1)处理对函数的不正确的调用。比如传入了错误的参数、返回值类型指定错了等。这部分cpython的libffi_msvc也没有做好,它做的仅仅是在windows下检测函数调用前后堆栈寄存器的位置是否一致,详见此处。但是仅有这个检测是不够的,它并不能有效的防止崩溃问题。我认为最好能做到能对参数、返回值进行类型检查,如果发现错误能打印错误,并且不进行函数的调用操作。

(2)如何在linux gcc环境下实现。

参考资料:

1、Reflection in C++ - a teaser

转载于:https://www.cnblogs.com/adinosaur/p/9787057.html

通过PDB文件实现非嵌入式的c++反射相关推荐

  1. 读懂蛋白质PDB文件

    对于从事生物行业的朋友们来说,PDB文件和蛋白质结构是很多人绕不过去的问题.然而对于天天跑电泳过柱子的生物狗来说,PDB文件打开后与天书无异.这里,我转载一篇网上看到的关于PDB文件内记号说明的文章, ...

  2. html嵌入war_WAR文件与具有嵌入式服务器的Java应用程序

    html嵌入war 大多数服务器端Java应用程序(例如,面向Web或面向服务的)都打算在容器中运行. 打包这些应用程序以进行分发的传统方法是将它们捆绑为WAR文件. 这只不过是具有标准目录布局的ZI ...

  3. WAR文件与具有嵌入式服务器的Java应用程序

    大多数服务器端Java应用程序(例如,面向Web或面向服务的)都希望在容器中运行. 打包这些应用程序以进行分发的传统方法是将它们捆绑为WAR文件. 这无非是具有标准目录布局的ZIP归档文件,其中包含运 ...

  4. 说说Debug文件夹下的.pdb文件

    .PDB文件,全称为"程序数据库"文件.我们使用它(更确切的说是看到它被应用)大多数场景是调试应用程序.目前我们对.PDB文件的普遍认知是它存储了被编译文件的调试信息,作为符号文件 ...

  5. 【vs调试】PDB文件:每个开发人员都必须知道的

    PDB文件:每个开发人员都必须知道的   一 什么是PDB文件 大部分的开发人员应该都知道PDB文件是用来帮助软件的调试的.但是他究竟是如何工作的呢,我们可能并不熟悉.本文描述了PDB文件的存储和内容 ...

  6. war3_WAR文件与带有嵌入式服务器的Java应用程序

    war3 大多数服务器端Java应用程序(例如,面向Web或面向服务的Java)旨在在容器中运行. 打包这些应用程序以进行分发的传统方法是将它们捆绑为WAR文件. 这无非是具有标准目录布局的ZIP归档 ...

  7. RDKit | 读取PDB文件并可视化

    导入库 from rdkit import rdBase from rdkit import Chem from rdkit.Chem import Draw from rdkit.Chem impo ...

  8. HTMD | 从PDB文件获取3D特征描述符

    KDEEP是使用深度学习(CNN)进行亲和力预测的预测器. 关于这篇文章,我发现了一个新的名为HTMD(高通分子动力学)的python库. 我真的不擅长从头算或MD计算等计算领域. 因此,我无法评估该 ...

  9. Pymol BioPython | PDB文件中氨基酸序列的提取

    1. Pymol 当前目录下有一个PDB文件,利用pymol的命令模式: pymol receptor.pdb -c -d "save receptor.fasta" 2. Bio ...

  10. Python:PDB文件中原子和残基重新编号

    Python脚本:PDB文件中原子和残基重新编号 Command: python renumber_pdb.py -i protein.pdb -a -r > output.pdb renumb ...

最新文章

  1. C#编程语言之常见的异常类型
  2. 注册不上zookeeper无报错_Zookeeper 跨区高可用方案
  3. 机器学习知识点(十六)集成学习AdaBoost算法Java实现
  4. WPF 绘制对齐像素的清晰显示的线条
  5. SVM支持向量机绘图
  6. 探索SwitchYard 2.0.0.Alpha2快速入门
  7. 最小公倍数 [最小公约数的拓展]
  8. win7 apache+php+mysql_win7下手动配置apache+php+mysql记
  9. Gitlab 服务器搭建,maven安装与jdk安装,linux下安装git
  10. Trello使用向导
  11. Java的throws Exception
  12. GPS原始坐标转百度地图坐标(纯C代码)
  13. 了解CV和RoboMaster视觉组(五)滤波器、观测器和预测方法:维纳滤波器Wiener Filter,LMS
  14. 计算机科学与技术专业大学四川省录取分数,四川人工智能专业大学分数线
  15. hdoj 1163 Eddy's digital Roots(数学问题,继续分析) .
  16. 汽车研发的五大阶段及制造的四大工艺
  17. 深度探索JFR - JFR详细介绍与生产问题定位落地 - 3. 各种Event详细说明与JVM调优策略(3)
  18. php获取汉字的首字母,PHP获取汉字的首字母
  19. ExoPlayer+Shaka-packager播放自制DRM视频
  20. tplink支持Linux的无线网卡,解决tp-link usb无线网卡在ubuntu14.04下无法使用的一种方法...

热门文章

  1. 主管好当:一不指点工作,二不检查工作,三不改正错误
  2. 编译telepresence:fatal error: libavfilter/avfiltergraph.h: 没有那个文件或目录
  3. 从最理想的情况论证自己的观点,必然错误,为什么明知故犯?
  4. 管理感悟:说说NWT裁员的经历及关键错误
  5. 管理感悟:严重问题与怪问题
  6. fork的写时复制1
  7. mac卸载python3.8_如何使用Homebrew在Mac上默认设置Python3.8?
  8. java web 网络安全_Java Web中的入侵检测及简单实现
  9. 实现带有拉普拉斯修正的朴素贝叶斯_数据科学 | 算法工程师必备的机器学习贝叶斯分类器...
  10. linux 测试网络端口通不通_能否使用一台矢量网络分析仪来控制多台 E5092A 以增加测试端口数?...