TCC研究(2) 把C语言当作脚本,解释执行,并嵌入各类程序
Tiny C Compiler(简称TCC,或Tiny CC)是世界上最小的C语言编译器。 TCC有1个突出的特点:就是可以把C语言当作脚本使用。试用记录以下:
首先,安装好TCC. 在Windows下, 下载履行程序: tcc-0.9.26-win32-bin.zip。 解压到c: cc,将c: cc添加到PATH目录中。 测试安装是不是成功,在命令行窗口中打入命令 tcc -v,看到TCC版本号即是成功
方式1: 以TCC解释履行C语言文本 解释履行,就是不编译,直接运行。 写1段C程序,存盘为 hello.c #include <stdio.h>
int main(int argc,char *argv[]) {
int i;
printf("Hello,world
");
for(i=1; i<argc; i++)
printf("argv[%d]=%s
",i,argv[i]);
} 在命令行窗口,打入命令 tcc -run hello.c
-run 的意思是立即履行 运行结果: Hello,world
还可以通过命令行,向程序传入参数 在命令行窗口,打入命令 tcc -run hello.c param1 param2 运行结果(显示有两个传入参数): Hello,world
方式2: 在Linux下,把C语言程序当作脚本运行,像SH脚本1样 首先,在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 则生成1个子目录 tcc-0.9.26,进入目录,编译它 cd tcc-0.9.26 ./configure make make install 完成后,输入命令 tcc -v . 如显示tcc版本号,表示成功。 用find命令查找1下 tcc 在哪? find / -name tcc 发现tcc可履行文件安装在 /usr/local/bin 写1段C程序,存盘为 hello.c #!/usr/local/bin/tcc -run
#include <stdio.h>
int main(int argc,char *argv[]) {
printf("Hello,world
");
} 第1行的 #!/usr/local/bin/tcc -run 是告知操作系统,这是1个脚本,解释器是 /usr/local/bin/tcc
修改权限,将hello.c 转为可履行文件 chmod +x hello.c 直接运行hello.c ./hello.c 运行结果: hello,world 感觉不错, .c文件直接当脚本
对照1下, 编译后再履行的情况 ,把hello.c编译1下: tcc hello.c , 将生成 a.out 运行a.out: ./a.out 运行结果与脚本履行1样 由于有第1行的 #!/usr/local/bin/tcc -run, 用gcc编译hello.c会出错,用tcc编译就没问题
嵌入脚本,就是让你的程序具有脚本功能,而且这个脚本还是C语言的。 tcc目录下的 exampleslibtcc_test.c是1个示范程序。 我觉得示范程序不通用,因而自己编了1个通用的模块,两个文件: cscript.c,cscript.h 先看 cscript.c, 定义了1个函数 run_script() 说明1下: libtcc.h 是 tcc提供的1个头文件,在tcc目录下复制过来的 #include <stdlib.h>
#include "libtcc.h" //TCC提供的头文件
/* 运行1个脚本,启动脚本中指定的函数,返回该函数的运行结果值
* 脚本中的启动函数原型必须为: 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); //1个函数指针, 函数原型为: int func(int param)
int result; //运行结果
s = tcc_new(); //初始化TCC编译引擎
if (!s) return ⑴; //初始化失败
//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) == ⑴) {
tcc_delete(s); return ⑵;
}
//如果程序重定位失败,退出
if (tcc_relocate(s,TCC_RELOCATE_AUTO) < 0) {
tcc_delete(s); return ⑶;
}
//寻觅名为function_name的入口函数
func = tcc_get_symbol(s,function_name);
if (!func) { //找不到入口函数,则退出
tcc_delete(s); return ⑷;
}
//运行入口函数,取得运行结果
result = func(param);
//结束TCC编译引擎
tcc_delete(s);
return result;
} 再看 cscript.h ,不过声明了1下run_script()这个函数。 #ifndef __CSCRIPT_H__
#define __CSCRIPT_H__
#ifdef __cplusplus
extern "C" {
#endif
/** 运行1个脚本,启动脚本中指定的函数,返回该函数的运行结果值
* 脚本中的启动函数原型必须为: int func(int param)
* programe是脚本程序,function_name是启动函数,param是传递给函数的参数
* tcc_path用于指定tcc所在目录,tcc_path设为NULL时表示不指定tcc目录
*/
extern int run_script(char *program,char *tcc_path);
#ifdef __cplusplus
}
#endif
#endif 好了, 编1个主程序,使用通用模块中的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_main
int param = 888; //传入参数
char *tcc_path = NULL;
int file_size;
int result; //返回结果
FILE *fp;
if (argc<=1) {
printf("Usage: cscript <script_file>
");
return ⑴;
}
//第1个命令行参数是脚本文件名,打开它
if ((fp=fopen(argv[1],"rb"))==NULL) {
printf("Error open file %s
",argv[1]);
return ⑴;
}
//测出文件长度
fseek(fp,0L,SEEK_END);
file_size = ftell(fp);
//申请1个内存用于寄存文件内容
program = (char *)malloc(file_size+1);
if (program==NULL) return ⑴;
//将文件内容全部读入到 program中
fseek(fp,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
",result);
}
free(program);
fclose(fp);
} 这个程序比较简单,不过是从命令行第1个参数指定的文件中,读出内容,当作脚本履行。
脚本中需要指定1个启动函数,这个函数不是main(),而是 int script_main(int param) 编译主程序(main.c 和 cscript.c), 假定tcc安装在c: cc目录下 tcc -llibtcc -Lc: cc main.c cscript.c -o cscript.exe -llibtcc 表示链接 libtcc库 (大小写不要写错) -Lc: cc 指定tcc目录(大小写不要写错) -o cscript.exe 指定生成exe文件为 cscript.exe 编译成功,没有任何提示。目录下生成 cscript.exe
好了,写1个脚本(内容以下),存盘为 test1.txt #include <stdio.h>
int script_main(int param)
{
printf("it's in script main,param =%d
",param);
return param;
} 用刚才生成的 cscript.exe 直接运行 test1.txt 打入命令 cscript test1.txt 运行结果: it's in script main,param =888 成功!! 这1次,我们不是使用tcc去运行脚本,而是采取刚才自己写的 cscript.exe程序去运行脚本。让自己的程序具有了脚本功能。 从TCC提供的example上看,TCC可以支持标准C,windows API调用,Linux动态库调用等,就是说,用脚本写系统程序、GUI,甚么都行。 相当于远程分发程序。 如何利用,看想像力了。比如说: 程序从网站下载1个文本,运行,生成1个GUI,产生1个小人在桌面上跑来跑去…… 再比如:大数据运算,100台计算机联网,某台机分发1个脚本,各机本地运算,返回结果给主机汇总,就是大数据的map-reduce算法嘛。 心有多远,就有多远 TCC就是强!
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |