TCC研究(2) 把C语言当作脚本,解释执行,并嵌入各类程序
来源:互联网 发布:禁忌的边界线知乎 编辑:程序博客网 时间:2024/05/01 12:24
Tiny C Compiler(简称TCC, 或Tiny CC)是世界上最小的C语言编译器。
TCC有一个突出的特点:就是可以把C语言当作脚本使用。试用记录如下:
首先,安装好TCC.
在Windows下, 下载执行程序: tcc-0.9.26-win32-bin.zip。 解压到c:\tcc, 将c:\tcc添加到PATH目录中。
测试安装是否成功,在命令行窗口中打入命令 tcc -v , 看到TCC版本号即是成功
方式一: 以TCC解释执行C语言文本
解释执行,就是不编译,直接运行。
写一段C程序,存盘为 hello.c
#include <stdio.h>int main(int argc, char *argv[]) { int i; printf("Hello, world\n"); for(i=1; i<argc; i++) printf("argv[%d]=%s\n", i, argv[i]);}在命令行窗口,打入命令 tcc -run hello.c
-run 的意思是立即执行
运行结果:
Hello, world
还可以通过命令行,向程序传入参数
在命令行窗口,打入命令 tcc -run hello.c param1 param2
运行结果(显示有两个传入参数):
Hello, world
argv[1]=param1
argv[2]=param2
方式二: 在Linux下,把C语言程序当作脚本运行,像SH脚本一样
首先,在Linux下安装TCC,我用的版本是Ubuntu 14.04
下载TCC源码,解压
cd ~
wget http://download.savannah.gnu.org/releases/tinycc/tcc-0.9.26.tar.bz2
tar xvf tcc-0.9.26.tar.bz2
则生成一个子目录 tcc-0.9.26,进入目录,编译它
cd tcc-0.9.26
./configure
make
make install
完成后,输入命令 tcc -v . 如显示tcc版本号,表示成功。
用find命令查找一下 tcc 在哪? find / -name tcc
发现tcc可执行文件安装在 /usr/local/bin
写一段C程序,存盘为 hello.c
#!/usr/local/bin/tcc -run#include <stdio.h>int main(int argc, char *argv[]) { printf("Hello, world\n");}第一行的 #!/usr/local/bin/tcc -run 是告诉操作系统,这是一个脚本,解释器是 /usr/local/bin/tcc
修改权限,将hello.c 转为可执行文件
chmod +x hello.c
直接运行hello.c
./hello.c
运行结果:
hello,world
感觉不错, .c文件直接当脚本
对比一下, 编译后再执行的情况 ,把hello.c编译一下: tcc hello.c , 将生成 a.out
运行a.out: ./a.out
运行结果与脚本执行一样
由于有第一行的 #!/usr/local/bin/tcc -run, 用gcc编译hello.c会出错,用tcc编译就没问题
方式三:在程序中嵌入脚本功能,动态调用C语言脚本(这是TCC的精华之处)
嵌入脚本,就是让你的程序具有脚本功能,而且这个脚本还是C语言的。
tcc目录下的 examples\libtcc_test.c是一个示范程序。
我觉得示范程序不通用,于是自己编了一个通用的模块,两个文件: cscript.c, cscript.h
先看 cscript.c, 定义了一个函数 run_script()
说明一下: libtcc.h 是 tcc提供的一个头文件,在tcc目录下复制过来的
#include <stdlib.h>#include "libtcc.h" //TCC提供的头文件/* 运行一个脚本, 启动脚本中指定的函数,返回该函数的运行结果值 * 脚本中的启动函数原型必须为: int func(int param) * program是脚本全部内容, function_name是启动函数名称,param是传递给函数的参数 * tcc_path用于指定tcc所在目录,tcc_path设为时NULL表示不指定tcc目录 */int run_script(char *program, char *function_name, int param, char *tcc_path){ TCCState *s; //TCC编译引擎 int (*func)(int); //一个函数指针, 函数原型为: int func(int param) int result; //运行结果 s = tcc_new(); //初始化TCC编译引擎 if (!s) return -1; //初始化失败 //tcc_path指定tcc所在的目录 if (tcc_path!=NULL) tcc_set_lib_path(s, tcc_path); //指明编译结果写入内存,而不是存为文件 tcc_set_output_type(s, TCC_OUTPUT_MEMORY);//如果编译失败,则退出 if (tcc_compile_string(s, program) == -1) { tcc_delete(s); return -2; } //如果程序重定位失败,退出 if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { tcc_delete(s); return -3; } //寻找名为function_name的入口函数 func = tcc_get_symbol(s, function_name); if (!func) { //找不到入口函数,则退出 tcc_delete(s); return -4; } //运行入口函数,获得运行结果 result = func(param); //结束TCC编译引擎 tcc_delete(s); return result;}
再看 cscript.h ,无非声明了一下run_script()这个函数。
#ifndef __CSCRIPT_H__#define __CSCRIPT_H__#ifdef __cplusplusextern "C" {#endif/** 运行一个脚本, 启动脚本中指定的函数,返回该函数的运行结果值 * 脚本中的启动函数原型必须为: int func(int param) * programe是脚本程序, function_name是启动函数,param是传递给函数的参数 * tcc_path用于指定tcc所在目录,tcc_path设为NULL时表示不指定tcc目录 */extern int run_script(char *program, char *function_name, int param, char *tcc_path);#ifdef __cplusplus}#endif#endif
好了, 编一个主程序,使用通用模块中的run_script()函数,每次通过命令行指定脚本文件,读出并运行。
假设主程序名为 cscript.exe
运行命令为: cscript <script_file>
主程序如下,存盘为 main.c
#include <stdio.h>#include <stdlib.h>#include "cscript.h" //通用模块头文件int main(int argc, char *argv[]){char *program = NULL; //脚本内容char *function_name = "script_main"; //启动函数名为script_mainint param = 888; //传入参数 char *tcc_path = NULL; int file_size;int result; //返回结果FILE *fp;if (argc<=1) { printf("Usage: cscript <script_file>\n");return -1;}//第一个命令行参数是脚本文件名,打开它if ((fp=fopen(argv[1],"rb"))==NULL) {printf("Error open file %s\n", argv[1]);return -1;}//测出文件长度fseek(fp, 0L, SEEK_END);file_size = ftell(fp);//申请一个内存用于存放文件内容program = (char *)malloc(file_size+1);if (program==NULL) return -1;//将文件内容全部读入到 program中fseek(fp, 0L, SEEK_SET);if (fread(program, file_size, 1, fp)>0) {program[file_size]=0;result = run_script(program, function_name, param, tcc_path);//运行printf("result = %d\n", result);}free(program);fclose(fp);}这个程序比较简单,无非是从命令行第一个参数指定的文件中,读出内容,当作脚本执行。
脚本中需要指定一个启动函数,这个函数不是main(), 而是 int script_main(int param)
编译主程序(main.c 和 cscript.c), 假设tcc安装在c:\tcc目录下
tcc -llibtcc -Lc:\tcc main.c cscript.c -o cscript.exe
-llibtcc 表示链接 libtcc库 (大小写不要写错)
-Lc:\tcc 指定tcc目录(大小写不要写错)
-o cscript.exe 指定生成exe文件为 cscript.exe
编译成功,没有任何提示。目录下生成 cscript.exe
好了,写一个脚本(内容如下),存盘为 test1.txt
#include <stdio.h>int script_main(int param){ printf("it's in script main, param =%d\n", param); return param;}
用刚才生成的 cscript.exe 直接运行 test1.txt
打入命令 cscript test1.txt
运行结果:
it's in script main, param =888
result = 888
成功!!
这一次,我们不是使用tcc去运行脚本,而是采用刚才自己写的 cscript.exe程序去运行脚本。让自己的程序具有了脚本功能。
从TCC提供的example上看,TCC可以支持标准C, windows API调用,Linux动态库调用等,就是说,用脚本写系统程序、GUI,什么都行。
相当于远程分发程序。
如何应用,看想像力了。比如说: 程序从网站下载一个文本,运行,生成一个GUI,产生一个小人在桌面上跑来跑去……
再比如:大数据运算,100台计算机联网,某台机分发一个脚本,各机本地运算,返回结果给主机汇总,就是大数据的map-reduce算法嘛。
心有多远,就有多远
TCC就是强!
- TCC研究(2) 把C语言当作脚本,解释执行,并嵌入各类程序
- TCC(Tiny C Compiler)用C语言当脚本例子
- 把程序当作人生
- 嵌入python脚本到c语言的应用(2)
- TCC研究(1): Tiny C Compiler最小的C语言编译器,自己编译自己
- Linux环境下c语言程序执行shell脚本
- python中嵌入C语言脚本
- C语言-程序中执行cmd命令并获取结果
- 执行脚本的C程序
- 在Android中嵌入C语言程序
- 嵌入开发中C语言程序优化
- 把人生当作程序来设计
- 在C/C++程序中嵌入perl解释器---注意事项
- 把程序作为人生,把人生当作程序
- 把程序作为人生,把人生当作程序
- 把程序作为人生,把人生当作程序
- 把程序作为人生,把人生当作程序
- 把程序作为人生,把人生当作程序!
- android 限制广播消息的接收者
- POJ 2540 Hotter Colder
- shell编程位置变量
- Motivated Word(3)
- C++BM算法
- TCC研究(2) 把C语言当作脚本,解释执行,并嵌入各类程序
- poj1019 Number Sequence
- 【BZOJ3209】花神的数论题 数位DP(我姿势不标准,但是可能更好写)
- The Third (构造函数,final )
- 远程触发SYSRQ获取最新的dmesg信息-一个几乎没有什么用的方案
- Spark源码走读4——Scheduler
- 007-读取游戏中的人物信息+输出调试信息 (郁金香老师 2015外挂教程)
- Sum It Up(HDU 1258)
- linux 交叉编译环境的搭建