C語(yǔ)言與Lua之間的相互調(diào)用詳解
前言
第一次接觸Lua是因?yàn)閁nity游戲中需要熱更,但是一直沒搞懂Lua是怎么嵌入到別的語(yǔ)言中執(zhí)行的,如何互相調(diào)用的。
lua是擴(kuò)展性非常良好的語(yǔ)言,雖然核心非常精簡(jiǎn),但是用戶可以依靠lua庫(kù)來(lái)實(shí)現(xiàn)大部分工作。除此之外,lua還可以通過與C函數(shù)相互調(diào)用來(lái)擴(kuò)展程序功能。在C中嵌入lua腳本既可以讓用戶在不重新編譯代碼的情況下修改lua代碼更新程序,也可以給用戶提供一個(gè)自由定制的接口,這種方法遵循了機(jī)制與策略分離的原則。在lua中調(diào)用C函數(shù)可以提高程序的運(yùn)行效率。lua與C的相互調(diào)用在工程中相當(dāng)實(shí)用,本文就來(lái)講解lua與C相互調(diào)用的方法。這次打算好好了解一下C跟lua是如何交互的
那么如何使用Lua語(yǔ)言?
lua是c語(yǔ)言編寫的,而且開源??梢栽趆ttps://www.lua.org官網(wǎng)上下載Lua的源碼,然后嘗試編譯它!是不是跟我一樣好激動(dòng),一直用集成環(huán)境,寫上層語(yǔ)言,今天居然要碰編譯了!!~ 可怎么編譯呢?
讓我們召喚出編譯神器:gcc!【GNU編譯器套件(GNU Compiler Collection)包括C、C++、Objective-C、Fortran、Java、Ada和Go語(yǔ)言的前端,也包括了這些語(yǔ)言的庫(kù)(如libstdc++、libgcj等等)?!?/p>
在Mac上安裝GCC
如果你安裝了Homebrew的話,只要一行就可以了。
brew install gcc
裝完后用
brew info gcc
或者
gcc -v
看一下是不是成功了
編譯Lua
當(dāng)你安裝好了編譯器后,編譯lua就變得非常簡(jiǎn)單了
Lua官網(wǎng)的文檔里有說編譯方式, 但MakeFile里默認(rèn)的是編譯成靜態(tài)鏈接庫(kù),被這個(gè)坑了,后面再說
建議安裝在/opt目錄下
sudo su cd /opt curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz tar zxf lua-5.3.4.tar.gz cd lua-5.3.4 make macosx test make macosx install
安裝好后用lua -v查看下如果有信息, 恭喜你,Lua編譯好了!~
下面正式開干了~
寫一個(gè)C調(diào)用Lua的Demo編譯運(yùn)行
add.c內(nèi)容
//你需要include這幾個(gè)lua頭文件
#include  <stdio.h>
#include  "lua.h"
#include  "lualib.h"
#include  "lauxlib.h"
lua_State* L;
int
luaadd(int x, int y)
{
 int sum;
 /*函數(shù)名*/
 lua_getglobal(L,"add");
 /*參數(shù)入棧*/
 lua_pushnumber(L, x);
 /*參數(shù)入棧*/
 lua_pushnumber(L, y);
 /*開始調(diào)用函數(shù),有2個(gè)參數(shù),1個(gè)返回值*/
 lua_call(L, 2, 1);
 /*取出返回值*/
 sum = (int)lua_tonumber(L, -1);
 /*清除返回值的棧*/
 lua_pop(L,1);
 return sum;
}
int
main(int argc, char *argv[])
{
 int sum;
 L = luaL_newstate(); /* 創(chuàng)建lua狀態(tài)機(jī) */
 luaL_openlibs(L); /* 打開Lua狀態(tài)機(jī)中所有Lua標(biāo)準(zhǔn)庫(kù) */
 /*加載lua腳本*/
 luaL_dofile(L, "add.lua");
 /*調(diào)用C函數(shù),這個(gè)里面會(huì)調(diào)用lua函數(shù)*/
 sum = luaadd(99, 10);
 printf("The sum is %d \n",sum);
 /*清除Lua*/
 lua_close(L);
 return 0;
}
add.lua放到與C同級(jí)的目錄下,里面寫一個(gè)簡(jiǎn)單的函數(shù),讓C調(diào)用
function add(x,y) return x + y end
好了,終于到了用GCC編譯的階段了,直接gcc add.c一下看看行不行。
果然報(bào)錯(cuò)了!
這是因?yàn)闆]有把a(bǔ)dd.c里面的函數(shù)鏈接到我們前面編譯出來(lái)的lua庫(kù)里導(dǎo)致的。怎么讓他指定鏈接哪個(gè)庫(kù)呢?看GCC的文檔得知-l參數(shù)可以指定要鏈接的庫(kù)
-l參數(shù)和-L參數(shù)
-l參數(shù)就是用來(lái)指定程序要鏈接的庫(kù),-l參數(shù)緊接著就是庫(kù)名,那么庫(kù)名跟真正的庫(kù)文件名有什么關(guān)系呢?
就拿數(shù)學(xué)庫(kù)來(lái)說,他的庫(kù)名是m,他的庫(kù)文件名是libm.so,很容易看出,把庫(kù)文件名的頭lib和尾.so去掉就是庫(kù)名了
那我們?cè)僭囈幌?,gcc add.c -llua,這次編譯出來(lái)了: a.out
執(zhí)行成功!
如何讓Lua調(diào)用C?
Lua調(diào)用C,我了解到的有3種方式
     1.通過在C中注冊(cè)函數(shù)給lua調(diào)用
     2.封裝成c動(dòng)態(tài)鏈接庫(kù),在lua中require
3.在LuaJIT里面可以使用ffi高性能的調(diào)用C(但是IOS上不支持LuaJIT。。)
1.在C中注冊(cè)函數(shù)給Lua
lua提供了lua_register函數(shù)注冊(cè)C函數(shù)給lua端調(diào)用
hello.c
#include  <stdio.h>
#include  <string.h>
#include  "lua.h"
#include  "lualib.h"
#include  "lauxlib.h"
static int l_SayHello(lua_State *L)
{
 const char *d = luaL_checkstring(L, 1);//獲取參數(shù),字符串類型
 int len = strlen(d);
 char str[100] = "hello ";
 strcat(str, d);
 lua_pushstring(L, str); /* 返回給lua的值壓棧 */
 return 1;
}
int
main(int argc, char *argv[])
{
 lua_State *L = luaL_newstate(); /* 創(chuàng)建lua狀態(tài)機(jī) */
 luaL_openlibs(L); /* 打開Lua狀態(tài)機(jī)中所有Lua標(biāo)準(zhǔn)庫(kù) */
 lua_register(L, "SayHello", l_SayHello);//注冊(cè)C函數(shù)到lua
 const char* testfunc = "print(SayHello('lijia'))";//lua中調(diào)用c函數(shù)
 if(luaL_dostring(L, testfunc)) // 執(zhí)行Lua命令。
  printf("Failed to invoke.\n");
 /*清除Lua*/
 lua_close(L);
 return 0;
}
gcc -o hello hello.c -llua編譯執(zhí)行
2.調(diào)用C動(dòng)態(tài)鏈接庫(kù)
創(chuàng)建一個(gè)mylib.c的文件,然后我們把它編譯成動(dòng)態(tài)鏈接庫(kù)
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
/* 所有注冊(cè)給Lua的C函數(shù)具有
 * "typedef int (*lua_CFunction) (lua_State *L);"的原型。
 */
static int l_sin(lua_State *L)
{ 
 // 如果給定虛擬棧中索引處的元素可以轉(zhuǎn)換為數(shù)字,則返回轉(zhuǎn)換后的數(shù)字,否則報(bào)錯(cuò)。
 double d = luaL_checknumber(L, 1);
 lua_pushnumber(L, sin(d)); /* push result */
 /* 這里可以看出,C可以返回給Lua多個(gè)結(jié)果,
  * 通過多次調(diào)用lua_push*(),之后return返回結(jié)果的數(shù)量。
  */
 return 1; /* number of results */
}
/* 需要一個(gè)"luaL_Reg"類型的結(jié)構(gòu)體,其中每一個(gè)元素對(duì)應(yīng)一個(gè)提供給Lua的函數(shù)。
 * 每一個(gè)元素中包含此函數(shù)在Lua中的名字,以及該函數(shù)在C庫(kù)中的函數(shù)指針。
 * 最后一個(gè)元素為“哨兵元素”(兩個(gè)"NULL"),用于告訴Lua沒有其他的函數(shù)需要注冊(cè)。
 */
static const struct luaL_Reg mylib[] = {
 {"mysin", l_sin},
 {NULL, NULL}
};
/* 此函數(shù)為C庫(kù)中的“特殊函數(shù)”。
 * 通過調(diào)用它注冊(cè)所有C庫(kù)中的函數(shù),并將它們存儲(chǔ)在適當(dāng)?shù)奈恢谩?
 * 此函數(shù)的命名規(guī)則應(yīng)遵循:
 * 1、使用"luaopen_"作為前綴。
 * 2、前綴之后的名字將作為"require"的參數(shù)。
 */
extern int luaopen_mylib(lua_State* L)
{
 /* void luaL_newlib (lua_State *L, const luaL_Reg l[]);
  * 創(chuàng)建一個(gè)新的"table",并將"l"中所列出的函數(shù)注冊(cè)為"table"的域。
  */ 
 luaL_newlib(L, mylib);
 return 1;
}
使用gcc -o mylib.so -fPIC -shared mylib.c -llua -ldl編譯成so
然后創(chuàng)建一個(gè)lua文件,把我們編譯出來(lái)的c庫(kù)引入進(jìn)來(lái)
--[[ 這里"require"的參數(shù)對(duì)應(yīng)C庫(kù)中"luaopen_mylib()"中的"mylib"。 C庫(kù)就放在"a.lua"的同級(jí)目錄,"require"可以找到。]] local mylib = require "mylib" -- 結(jié)果與上面的例子中相同,但是這里是通過調(diào)用C庫(kù)中的函數(shù)實(shí)現(xiàn)。 print(mylib.mysin(3.14 / 2)) --> 0.99999968293183
執(zhí)行a.lua文件,后報(bào)錯(cuò),說Lua存在多個(gè)虛擬機(jī)!
lua: multiple Lua VMs detected
為什么呢?查了一些資料發(fā)現(xiàn)因?yàn)閘ua默認(rèn)編譯的是靜態(tài)鏈接庫(kù),這樣會(huì)導(dǎo)致鏈接多個(gè)VM沖突。
那么我們自己再編譯個(gè)lua解釋器動(dòng)態(tài)鏈接一下。
mylua.c
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main() {
 lua_State *L = luaL_newstate();
 luaL_openlibs(L);
if (luaL_loadfile(L, "a.lua") || lua_pcall(L, 0, 0, 0)) {
  printf("%s", lua_tostring(L, -1));
 }
}
gcc -o mylua mylua.c -llua -ldl -lm -Wall
這樣就能編譯出mylua可執(zhí)行文件
在命令行./mylua執(zhí)行,成功打印出0.99999968293183
總結(jié)
gcc命令,編譯lua,編譯C動(dòng)態(tài)鏈接庫(kù)這些之前都接觸的比較少。所以也爬了不少坑,哈哈哈。接下來(lái)要好好研究下怎么在c中解析二進(jìn)制協(xié)議給lua調(diào)用,在c中怎么封裝好luatable
參考資料:
- https://www.cnblogs.com/pied/archive/2012/10/26/2741601.html
 - http://blog.csdn.net/vermilliontear/article/details/50947379
 - http://blog.csdn.net/casularm/article/details/316149
 
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)我們的支持。
上一篇:C語(yǔ)言實(shí)現(xiàn)歌曲信息管理系統(tǒng)
欄 目:C語(yǔ)言
下一篇:Qt實(shí)現(xiàn)保存、瀏覽、預(yù)覽、打印功能的示例代碼
本文標(biāo)題:C語(yǔ)言與Lua之間的相互調(diào)用詳解
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/957.html
您可能感興趣的文章
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用函數(shù)刪除字符
 - 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)式函數(shù)庫(kù)
 - 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
 - 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
 - 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段函數(shù)
 - 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排序法函數(shù)
 - 04-02c語(yǔ)言沒有round函數(shù) round c語(yǔ)言
 - 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段函數(shù)
 - 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
 - 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求階乘
 


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
 - 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
 - 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
 - 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
 - 5c語(yǔ)言計(jì)算三角形面積代碼
 - 6什么是 WSH(腳本宿主)的詳細(xì)解釋
 - 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
 - 8正則表達(dá)式匹配各種特殊字符
 - 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
 - 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
 
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
 - 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
 - 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
 - 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
 - 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
 - 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
 - 04-02c語(yǔ)言沒有round函數(shù) round c語(yǔ)言
 - 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
 - 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
 - 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
 
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
 - 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
 - 04-02jquery與jsp,用jquery
 - 01-10delphi制作wav文件的方法
 - 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
 - 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
 - 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
 - 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
 - 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
 - 01-10C#中split用法實(shí)例總結(jié)
 


