TCC研究(2) 把C語言當作指令碼,解釋執行,並嵌入各類程式

來源:互聯網
上載者:User

標籤:c

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) return -2;    //如果程式重定位失敗,退出    if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) return -3;    //尋找名為function_name的入口函數    func = tcc_get_symbol(s, function_name);    if (!func) 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;//將檔案內容全部讀入到 progarme中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語言當作指令碼,解釋執行,並嵌入各類程式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.