实时编译、动态执行C/C++源码函数

         语法格式:fileCLASS *pObj = <file.cpp>

该语法获得源代码file.cpp的函数接口对象指针pObj,通过pObj调用file.cpp的
函数。
参数: file.cpp: c/c++源代码文件名。
返回值:fileCLASS *pObj: 接口对象地址。

1. 编写c/c++源码函数接口

struct rootCLASS    //函数对象名字
{virtual char* _stdcall getstr(char *aptr);                   //定义函数0virtual void _stdcall getval(double aval,char *aptr);        //定义函数1virtual double _stdcall sqrt(int aval);                      //定义函数2
};
头文件: root.h (定义了3个接口函数)
#include "root.h"           //定义对象的头文件
char* rootCLASS::getstr(char *aptr)     //实现函数0
{printf("江南好\n%s",aptr);return `日出江花红似火, `;
}void rootCLASS::getval(double aval,char *aptr)          //实现函数1
{double dd = aval + 0.00002227;printf(`春来江水绿如蓝 -- "%0.8f"\n%s\n`,dd,aptr);
}double rootCLASS::sqrt(int aval)     //实现函数2
{return ::sqrt(aval);
}rootCLASS ROOT;           //声明接口变量
void* main(void **pObj)
{*pObj = &ROOT;    //把接口地址传给用户return []()       //返回Lambda函数用于资源清理{printf("Exit.\n");};
}
c/c++文件: root.cpp (实现源码函数接口)

2.编写程序调用root.cpp的函数

#include "root.h"     //定义ROOT对象的头文件
void main()
{rootCLASS *ROOT = <root.cpp>;         //该语句取出root.cpp的函数对象地址if(!ROOT) return;                     //若root.cpp有语法错误,则ROOT=nullprintf("%s\n",ROOT->getstr("风景旧曾谙\n"));   //调用root.cpp的getstr函数ROOT->getval(2014.0720,"能不忆江南");          //调用root.cpp的getval函数printf("%f\n",ROOT->sqrt(3));                  //调用root.cpp的sqrt函数
}
c/c++文件: like.cpp (调用root.cpp函数)

编译执行:
用YC命令: ycc like.cpp 生成 like.exe。执行like.exe后,输出下列文字:
江南好
风景旧曾谙
日出江花红似火,
春来江水绿如蓝 – “2014.07202227”
能不忆江南
1.732051
Exit.

分析:

  1. 文件root.cpp和root.h一起为应用程序提供一个函数接口:rootCLASS ROOT。

  2. 语句rootCLASS *ROOT = <root.cpp>将源代码root.cpp编译转换为执行代码文件:
    www \…root.cpp.exp
    之后执行代码被调入内存,like.cpp变量rootCLASS ROOT的地址被传给root.cpp的主函数:void main(void **pObj){},主函数通过语句 *pObj = &ROOT 把root.cpp的函数接口对象地址&ROOT传给like.cpp的rootCLASS *ROOT。
    like.cpp通过语句下列语句:
    ROOT->getstr()
    ROOT->getval()
    ROOT->sqrt()
    调用root.cpp的接口函数。

  3. 程序退出时,自动检查root.cpp主函数main()是否有函数指针返回,若有,则执行它,以便释放root.cpp可能申请的系统资源。本例root.cpp主函数的返回值为lambda函数:{ printf(“Exit.\n”); };

  4. 将root.cpp调入YC编辑器后,按Ctrl+F5键,生成下列汇编代码,分析汇编代码可更好
    地理解接口源码。

#include   "root.cpp"               2020-01-11  12:40:30     0
#include   "include/ycapi.h"        2020-01-10  14:39:02     1
#include   "root.h"                 2020-01-10  17:38:26     20    printf1    sqrtvoid entry()
{
00000000 6800000000   push   0x00000000
00000005 e802000000   call   void *main(void **pObj) (0000000C=000000A+0000002)//root.cpp 21
0000000A 59           pop    ecx
0000000B c3           ret
}root.cpp 20  arglen=4
void *main(void **pObj)
{
0000000C 8b442404       mov   eax,dword [esp+04h]
00000010 c700d8000000   mov   dword [eax],0x000000D8  //struct rootCLASS ROOT (root.cpp 19)
00000016 b884000000     mov   eax,0x00000084    //global=00000017   返回函数的地址
0000001B c3             ret
}root.h 3  arglen=8root.cpp 3
virtual char *stdcall rootCLASS::getstr(char *aptr)
{
0000001C 55             push    ebp
0000001D 8bec           mov     ebp,esp
0000001F 51             push    ecx
00000020 ff750c         push    dword [ebp+0Ch]        //aptr   (root.cpp 2)
00000023 6890000000     push    0x00000090        //"江南好\n%s"  (root.cpp 4)
00000028 e87fdbff8e     call    int printf(const char *_Format, ...) //include/stdio.h 264
0000002D 83c408         add     esp,0x00000008
00000030 b89c000000     mov     eax,0x0000009C        //"日出江花红似火, "  (root.cpp 5)
00000035 8be5           mov     esp,ebp
00000037 5d             pop     ebp
00000038 c20800         ret     0008
}root.h 4  arglen=10root.cpp 9
virtual void stdcall rootCLASS::getval(double aval,char *aptr)
{
0000003B 55             push    ebp
0000003C 8bec           mov     ebp,esp
0000003E 83ec0c         sub     esp,0x0000000C
00000041 dd450c         fld     qword [ebp+0Ch]        //aval   (root.cpp 8)
00000044 dc05e8000000   fadd    qword [000000E8]       //zeroName  (include/yca.h 0)
0000004A dd5df8         fstp    qword [ebp-08h]        //dd   (root.cpp 10)
0000004D ff7514         push    dword [ebp+14h]        //aptr   (root.cpp 8)
00000050 ff75fc         push    dword [ebp-04h]        //dd+4 (00064c99 + 4)  (root.cpp 10)
00000053 ff75f8         push    dword [ebp-08h]        //dd   (root.cpp 10)
00000056 68b0000000     push    0x000000B0             //"春来江水绿如蓝 -- \"%0.8f\"\n%s\n"
0000005B e87fdbff8e     call    int printf(const char *_Format, ...) (8EFFDB7F)//stdio.h 264
00000060 83c410         add     esp,0x00000010
00000063 8be5           mov     esp,ebp
00000065 5d             pop     ebp
00000066 c21000         ret     0010
}root.h 5  arglen=8root.cpp 15
virtual double stdcall rootCLASS::sqrt(int aval)
{
00000069 55             push        ebp
0000006A 8bec           mov         ebp,esp
0000006C 51             push        ecx
0000006D db450c         fild        dword [ebp+0Ch]        //aval   (root.cpp 14)
00000070 83ec08         sub         esp,0x00000008
00000073 dd1c24         fstp        qword [esp]
00000076 e820dbff8e     call        double sqrt(double _X) (8EFFDB20) //include/math.h 521
0000007B 83c408         add         esp,0x00000008
0000007E 8be5           mov         esp,ebp
00000080 5d             pop         ebp
00000081 c20800         ret         0008
}root.cpp 23  arglen=0
void stdcall lamb_0000032()    //Lambda函数虽在局部定义,却在全局实现
{
00000084 68d0000000     push      0x000000D0        //"Exit.\n"  (root.cpp 25)
00000089 e87fdbff8e     call      int printf(const char *_Format, ...) //include/stdio.h 264
0000008E 59             pop       ecx
0000008F c3             ret
}// strings 代码中所用到的字符串
00000090        db    12    "江南好\n%s"                         //root.cpp 4
0000009C        db    20    "日出江花红似火, "                   //root.cpp 5
000000B0        db    32    "春来江水绿如蓝 -- \"%0.8f\"\n%s\n"  //root.cpp 11
000000D0        db     8    "Exit.\n"                            //root.cpp 25// variables 用户声明或编译器自动生成的全局变量 ///
000000D8        struct rootCLASS ROOT                                           dd  000000DC
000000DC        virtual char *stdcall rootCLASS::getstr(char *aptr)             dd  0000001C
000000E0        virtual void stdcall rootCLASS::getval(double aval,char *aptr)  dd  0000003B
000000E4        virtual double stdcall rootCLASS::sqrt(int aval)                dd  00000069
000000E8        zeroName                                                dq  3EF75A0EBF358A7B
000000F0 The End  -  240 bytes
// stack = 1 * 1048576 bytes
  1. 看看下面like.cpp的汇编代码(在YC编辑器的工具菜单中生成),有助于理解该语法的实
    现过程。
#include   "like.cpp"                       2020-01-11  09:30:08     0
#include   "include/ycapi.h"                2020-01-10  14:39:02     1
#include   "root.h"                         2020-01-10  17:38:26     20    YC_ExpFree1    YC_ExpLoad2    printflike.cpp 2  arglen=0
void main()
{
00000000 53              push   ebx        //ebx=ROOT   (like.cpp 4)
00000001 68a0000000      push   0x000000A0        //zeroName  (include/yca.h 0)
00000006 68a4000000      push   0x000000A4        //zeroName  (include/yca.h 0)
0000000B 68a8000000      push   0x000000A8        //zeroName  (include/yca.h 0)
00000010 e8f2d8ff8e      call   void stdcall YC_ExpLoad(void *pSrc,void *pHandle,void *pObj)
00000015 8b1da0000000    mov    ebx,dword [000000A0] //zeroName  (include/yca.h 0)
0000001B 85db            test   ebx,ebx
0000001D 744e            je     0000006D = 0000001F+0000004e
0000001F 6884000000      push   0x00000084        //"风景旧曾谙\n"  (like.cpp 6)
00000024 8bcb            mov    ecx,ebx
00000026 51              push   ecx
00000027 8b01            mov    eax,dword [ecx]
00000029 ff10            call   dword [eax]       //调用ROOT->getstr()
0000002B 50              push   eax
0000002C 6880000000      push   0x00000080        //"%s\n"  (like.cpp 6)
00000031 e87fdbff8e      call   int printf(const char *_Format, ...) //include/stdio.h 264
00000036 83c408          add    esp,0x00000008
00000039 6890000000      push   0x00000090        //"能不忆江南"  (like.cpp 7)
0000003E 6849789f40      push   0x409F7849
00000043 683f355eba      push   0xBA5E353F
00000048 8bcb            mov    ecx,ebx
0000004A 51              push   ecx
0000004B 8b01            mov    eax,dword [ecx]
0000004D ff5004          call   dword [eax+04h]     //调用ROOT->getval()
00000050 6a03            push   0x00000003
00000052 8bcb            mov    ecx,ebx
00000054 51              push   ecx
00000055 8b01            mov    eax,dword [ecx]
00000057 ff5008          call   dword [eax+08h]    //调用ROOT->sqrt()
0000005A 83ec08          sub    esp,0x00000008
0000005D dd1c24          fstp   qword [esp]
00000060 689c000000      push   0x0000009C        //"%f\n"  (like.cpp 8)
00000065 e87fdbff8e      call   int printf(const char *_Format, ...) //include/stdio.h 264
0000006A 83c40c          add    esp,0x0000000C
0000006D 5b              pop    ebx
0000006E c3              ret
}void yc_end()  //由编译器根据是否有需要释放的资源而自动生成的函数,程序退出时自动执行
{
0000006F 68a4000000   push   0x000000A4        //zeroName  (include/yca.h 0)
00000074 68a8000000   push   0x000000A8        //zeroName  (include/yca.h 0)
00000079 e8f3d8ff8e   call   void stdcall YC_ExpFree(void *pSrc,void *pHandle) //yca.h 133
0000007E c3           ret
}// strings 代码中所用到的字符串
00000080        db     4    "%s\n"                      //like.cpp 6
00000084        db    12    "风景旧曾谙\n"              //like.cpp 6
00000090        db    12    "能不忆江南"                //like.cpp 7
0000009C        db     4    "%f\n"                      //like.cpp 8// variables用户声明或编译器自动生成的全局变量 //
000000A0        zeroName         dd  00000000    //ldpos=000000A0      include/yca.h 0
000000A4        zeroName         dd  00000000    //include/yca.h 0
000000A8        zeroName         dd  00000000    //include/yca.h 0
000000AC The End  -  172 bytes

语法细节:

1. 语句后面可跟0、1、2、3四个数字,其意义如下:
ROOT = <root.cpp> 0;  pmt方式,是默认方式,0可省略。该方式中,root.cpp的执行
代码保存在www\…root.cpp.exp文件,如果修改root.cpp,则执
行like.exe时将重新编译root.cpp,若root.cpp有语法错误,
便弹出错误提示菜单,退出菜单后继续执行后面的代码。
ROOT = <root.cpp> 1;  mem方式。该方式中,编译后的root.cpp执行代码被保存在
like.exe文件,root.cpp的改动不会影响like.exe的执行。
ROOT = <root.cpp> 2;  nopmt方式。该方式中,root.cpp的执行代码保存在
www\…root.cpp.exp文件,如果修改root.cpp,则执行like.exe
时将重新编译root.cpp,若root.cpp有语法错误,不提示而继
续执行后面的代码。
ROOT = <root.cpp> 3;  exit方式。该方式中,root.cpp的执行代码保存在
www\…root.cpp.exp文件,如果修改root.cpp,则执行like.exe
时将重新编译root.cpp,若root.cpp有语法错误,便弹出错误
提示菜单,退出菜单后便退出整个程序。2. 除方式1外,应该用语句 if(!ROOT){……} 判断root.cpp是否有语法错误。
如果.cpp文件不存在,则调用同名的.exp文件。如果.cpp或.exp文件在当前目录不存
在,则在src目录寻找。
3. 在yc.h中定义了下列4个宏:
#define CPP_pmt    0
#define CPP_mem    1
#define CPP_nopmt  2
#define CPP_exit   3
可以使用这4个宏指定该语法的运行方式。
4. 用VC++等其它编译器开发的程序不能使用该语法,但它们通过下面两个API函数可实
现本语法的功能。
void *YC_cppLoad(const char *srcbuf,int srclen, void *pObj,int isScript=0);
void YC_cppFree(void *pHandle);
5. YC开源代码中,下列文件使用了该语法。
ycweb.cppYCJS = YCWEB.ycjs = <ycjs.cpp>;YCDRAW = YCWEB.ycdraw = <ycdraw.cpp>;YCHTML = YCWEB.ychtml = <ychtml.cpp>;YCWEB.ycjit = <ycjit.cpp>;YCWEB.yckit = <yckit.cpp>;YCWEB.ycrend = <ycrend.cpp>;YCWEB.ycsock = <ycsock.cpp>;
ycjs.cppYCCSS = YCJS.yccss = <yccss.cpp>;YCOBJ = YCJS.ycobj = <ycobj.cpp>;YCSTRING = YCJS.ycstring = <ycstring.cpp>;YCARRAY = YCJS.ycarray = <ycarray.cpp>;YCDATE = YCJS.ycdate = <ycdate.cpp>;YCDOM = YCJS.ycdom = <ycdom.cpp>;YCJS.ycrange = <ycrange.cpp>;YCJS.ycajax = <ycajax.cpp>;YCJS.ycdb = <ycdb.cpp>;
ycdraw.cpp ycx_ImageLoad = <ycimage.cpp> CPP_exit;
ycstring.cppYCREGEX = <ycregex.cpp>CPP_exit;
ycrend.cppYCTABLE = <yctable.cpp>;
ychtml.cppYCFILTER = <ycfilter.cpp>;YCFRAMESET = <ycframeset.cpp>;
ycs.htmychttpCLASS *YCHTTP = <ychttp.cpp>;
yc.cppycwinCLASS *pwin = <ycwin.cpp>;

实时编译、动态执行C/C++源码函数相关推荐

  1. 【动态代理】从源码实现角度剖析JDK动态代理

    相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象.动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代 ...

  2. NanoPi NEO Air使用七:获取并编译U-boot和Linux的源码

    NanoPi NEO Air使用一:介绍 NanoPi NEO Air使用二:固件烧录 NanoPi NEO Air使用三:OverlayFS.CPU温度和频率.wifi.蓝牙.npi-config ...

  3. 汇编 debug调试没有执行对应文件源码指令---》失灵---》正确使用debug第一步

    汇编 debug调试时 没有执行 对应文件源码指令 果然不认真听课就是这样 把调试命令 debug test.exe 错误写成 debug test.asm 并一直使用多达两周时长 我真是个人才Σ( ...

  4. Ubuntu16.04编译Android 6.0系统源码过程简要记录总结

    一,安装VMware Workstation,百度网盘下载(内含注册机) 链接: https://pan.baidu.com/s/1wz4hdNQBikTvyUMNokSVYg 提取码: yed7 V ...

  5. 一文读懂Spring动态配置多数据源---源码详细分析

    Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 代云小说网 https://www.3187.info ​ 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批 ...

  6. 用腾讯即时通讯IM和实时音视频实现陪玩系统源码的语音通话功能

    在陪玩系统源码中,用户之间主要的交流方式就是语音通话,实时互动性的语音通话能让人产生面对面交谈的感觉,所以在陪玩系统源码中,语音通话功能的开发非常重要,今天我们就一起来看看如何用腾讯即时通讯IM和实时 ...

  7. 反编译python 生成的exe源码

    反编译python 生成的exe源码 记录反编译exe工具使用 工具准备 – pyinstxtractor.py – uncompyle6 – sublime Text(或者其他的二进制编辑工具) 一 ...

  8. 壁纸背景墙/头像/动态壁纸小程序源码-支持用户投稿-带部分采集功能+搭建教程

    介绍: 今天自己搭建测试了一下这款背景墙/头像/动态壁纸小程序源码,源码使用dcloud云开发 (云开发优势:无需服务器域名直接搭建部署即可,成本低方便维护.)支持微信QQ双端小程序也就是说可以打包成 ...

  9. android 3.10. 内核,编译android 3.10内核源码时出错

    最近我尝试为我的xiaomi mi4c交叉编译android内核. 要做到这一点,我已经下载并这样配置的工具链:从这里编译android 3.10内核源码时出错 git clone https://a ...

最新文章

  1. 开发日记-20190707 关键词 读书笔记 《Perl语言入门》Day 4
  2. spring18-4: spring aop
  3. Java使用继承的语法是,Java使用继承
  4. HTML特殊编码转换
  5. ElementUI中实现表单刷新重置,保存在全局方法中
  6. OpenSSL--Window生成证书实战
  7. 如何解决IE6的3像素问题?
  8. Android 应用开发(33)---Android程序签名打包
  9. JavaScript版代码执行
  10. 规则引擎--规则引擎构成重点
  11. bat与jscript开发工具时遇到的一些问题
  12. opnet如何进行C语言编程,OPNET学习小记(五)
  13. Android手机无法上网怎么办,为什么android手机已经连接WIFI还是不能上网?
  14. Scum服务器显示红色,进服务器 提示这个有大神解答一下吗
  15. matlab不连续分段函数,分段函数画出的曲面不连续如何办?
  16. passw、shadow、group文件详解
  17. 建议收藏:Axure交互常用按钮组
  18. HTML CSS JS基础
  19. PM、RD、FE、UE...等等这些互联网相关的缩写
  20. 华恩JAVA班第22天

热门文章

  1. 2022年河南工业大学专升本2022年河南工业大学专升本(解答)
  2. K-Means检测DGA域名
  3. 打开ssh通道是什么意思_PP助手里有一个“打开SSH通道”SHH是什么?能干什么?...
  4. 【它山之玉】关于年龄的焦虑的一些安慰
  5. 验证一个十六进制的颜色是否合法 合法的字符: #000 #fff #FFF #000000 #ffffff #FFFFFF
  6. 通过配置环境变量解锁win+r新玩法
  7. QQ通信原理--转载
  8. 11 Confluent_Kafka权威指南 第十一章:流计算
  9. 手把手教你在ARM嵌入式开发板上只做自己的人脸识别装置
  10. RTF(富文本格式)与HTML(超文本标记语言)的区别?