使用tolua 實現C 與LUA相互呼叫

2021-08-09 17:03:50 字數 3788 閱讀 7618

lua是一種目前很流行的高效精簡的指令碼語言。lua乙個特點是比較方便的與c通訊。

然而要在指令碼中使用c++類使用基本的lua方法還是比較麻煩,純手工暴露乙個類的介面到lua工作量還是很大的,而且都是一些簡單的重複勞動。

好在有tolua++這個工具,可以讓程式設計師從簡單的重複勞動解脫出來。

tolua++包含兩個部分,乙個exe,乙個lib,exe用來通過package檔案生成c函式的膠水函式,而lib則用來為生成的膠水函式中用到的輔助函式提供實現。

在lua中要呼叫乙個已有的c函式,大體上可以包含2步:

1、在c程式中實現乙個膠水函式,該函式只有乙個引數lua_state *。在這個膠水函式中,從lua的引數棧中逐個取出引數,再呼叫原有的c函式,最後將c函式的返回結果通過lua的棧傳回給lua環境。

2、將該膠水函式註冊到lua的全域性表中。

雖然這兩個過程都很簡單,但是當要暴露的是c++類大量的成員函式時,為每個函式編寫膠水函式的工作可想而知。

有了tolua++,這個工作就很簡單了,只需要做很少的工作就可以讓tolua++自動為每乙個待暴露的函式實現膠水函式。

如下面這樣乙個c++類,類的實現在乙個命名空間tstns中,類中包含有同一函式名的不同過載及自定義的結構體引數:

#pragma once

#include

using namespace std;

namespace tstns

;class cexport;}

為了使用tolua++匯出這個類到lua中,我們需要寫乙個package檔案,在該檔案中定義**函式需要匯出,我這裡的實現如下:

$#include "export.h"

namespace tstns;

class cexport;}

整 體上export.pkg中的內容基本與export.h檔案類似,需要注意的是第一行:$#include "export.h"。tolua++根據這個檔案來為其中的每個函式生成膠水函式於乙個c檔案中,由於膠水函式需要呼叫原來的函式,所以需要在生成的c 檔案中需要包含export.h這個檔案。第一行就是說在生成的c檔案中插入一行#include 「export.h"

第二個需要注意的地方在於函式的過載,lua並不能根據參考型別自動選擇呼叫哪乙個過載函式,為此我們可以為不同的重載重命名。」@「正是為這一目的設計的。通過重新命名,在lua指令碼中我們就可以顯示的為不同的引數呼叫不同的過載函式。

我們需要使用tolua++的exe來生成膠水函式**。它是乙個命令列程式,可以多個引數:

..\..\tolua++-1.0.93\bin\tolua++ -n export -o ..\lua_export.cpp export.pkg

這一行的意思是說呼叫tolua++.exe根據export.pkg生成乙個..\lua_export.cpp的c++檔案。-n export是說檔案中乙個需要被外面呼叫的c介面為:

int tolua_

export_open (lua_state* tolua_s);

下一步,我們看一下在lua指令碼中如何呼叫我們的匯出的函式。

--file:test.lua

exp=tstns.cexport:new();--首先我例項化乙個cexport的全域性物件。

function foo(a,b)

return exp:foo(a,b);

endfunction strlen(str)

return exp:strlen(str);

endfunction strlen2(str)

return exp:strlen2(str);

endfunction area(rc)

return exp:area(rc);

endfunction area2(prc)

--指標引數使用lua_call.hpp將以void*方式傳入,需要做型別轉換後才能呼叫c++中的**。

return exp:area2(tolua.cast(prc,"tstns::rect"));

endfunction setrect(l,t,r,b)

return exp:setrect(l,t,r,b);

end在這個test.lua中我們實現了幾個函式,在每乙個函式中會呼叫cexport對應的介面。

到此lua呼叫c++的基本框架就已經實現了。

下面再看這個demo如何工作。

找到**中的luatest目錄,並開啟luatest.sln這個vc工程,上面提到的**在工程中都可以找到。

直接編譯可以檢視每乙個函式是如何被呼叫的。

這裡要推薦乙個我改寫的在c++中呼叫lua函式的輔助模板類:lua_call.hpp

採用這個輔助類呼叫lua函式就和呼叫普通的c函式一樣簡單。

下面是luatest.cpp中的**:

// luatest.cpp : 定義控制台應用程式的入口點。 //

#include "stdafx.h"

#include "export.h"

#include "tolua++.h"

extern int  tolua_export_open (lua_state* tolua_s);

#include "lua_call.hpp"

//使用模板技術對c++呼叫lua函式進行包裝,使用方法參見_tmain

//對於自定義的資料型別,需要特化push_value,及value_extractor兩個介面。

template<>

void lua_function_base::push_value(tstns::rect rc)

template <>

tstns::rect lua_function_base::value_extractor()

int _tmain(int argc, _tchar* argv) ;

int a1=lua_area(rc);

lua_functionlua_area2(l,"area2");

tstns::rect rc2=;

int a2=lua_area2(&rc2);

lua_functionlua_setarea(l,"setrect");

rc=lua_setarea(5,6,7,8);

lua_functionlus_strlen(l,"strlen");

int nsize1=lus_strlen(std::string("abcdefghij"));

lua_functionlus_strlen2(l,"strlen2");

int nsize2=lus_strlen("abcdefg");

lua_functionfoo(l,"foo");

int sum=foo(5,6); }

lua_close(l);

return 0; }

在_main()中,首先當然是例項化lua環境。

呼叫tolua_export_open(l);註冊tolua++實現的膠水函式到lua。

呼叫lual_dofile(l,"lua/test.lua");執行test.lua指令碼。

呼叫lua指令碼中實現的函式。

最後釋放lua環境:lua_close(l);

這其中lua指令碼中實現的函式是比較取巧的。利用lua_call.hpp,我們只需要兩行**就可以實現:

第一步,定義乙個lua_function物件,找到lua中的函式。

第二步,為函式傳入引數。

需要注意的是,當為cexport新增加乙個需要匯出的函式時,要記得將新的函式名加到export.pkg檔案中,並呼叫tolua++重新生成膠水函式。在demo中有乙個build.bat檔案,每次更新後執行一次即可。

lua呼叫c 的函式 使用tolua

1.定義c 類與函式 include class cppfunctions include cppfunctions.h include include 使用linux下獲取時間的函式 double cppfunctions getcurrenttime 2.繫結 我新建了乙個tolua.h和乙個t...

lua與C(一) C呼叫lua

lua和c有兩種關係 一種是在lua中呼叫c的函式,c稱為庫 一種是c中呼叫lua,c就稱為應用程式 此時c中包含了lua的直譯器 c 部分 注意在c 中,通常要把lua的一些標頭檔案定義在extern c 中,因為他們是c語言實現的。1.作為應用程式呼叫lua char buffer print ...

使用lua實現nginx rewrite

上一次上線只是簡單的把手機端的流量切換手機端的首頁,有點粗糙,現在需要把電腦端相應的頁面切換到電腦端的頁面,直接用nginx自帶的rewrite不太好做,所以用lua做 下面開始 nginx 配置 location mobile.lua 手機訪問重定向到移動版 end其實邏輯也很簡單,主要在ngin...