日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Lua5.3 与C交互学习(一)

發布時間:2023/12/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Lua5.3 与C交互学习(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

    • C++中引入lua環境搭建
    • C++調用Lua函數
    • Lua中調用C++函數
    • .lua文件文間之間的全局變量調用
    • 引入C模塊到 lua
    • lua5.3 C++注冊函數或模塊到lua
    • 注冊C++類到lua
    • C++ struct對應到lua table

C++中引入lua環境搭建

  • 第一種: 聯合的方式(不方便)
  • 下載lua5.3.1 tar.gz
  • 創建控制臺項目, 靜態庫, 取消預編譯頭;
  • C/C++>常規>附加包含目錄: 加入5.3.1\src
  • 編譯得到lublib.lib
  • 創建新工程
  • 在vc++目錄里添加包含目錄 和庫目錄;
  • 連接器里添加lualib.lib
  • 編譯; 如果失敗則拷貝lualib.lib到根目錄dubug下;
  • OK
  • 第二中: 生成靜態庫
  • 新建控制臺項目, 靜態庫, 取消預編譯頭;
  • 將5.3.2的src中添加到項目中, 但 不要添加lua.c
  • 編譯得到xxx.lib, 這就是所得到的靜態庫
  • 建立一個文件夾如lua5.3,分別在子文件夾lib里放入剛生成的xxx.lib(可以改名為lua5.3.2.lib)和include子文件夾里放入lua頭文件: lauxlib.h, lua.h, luaconf.h, lualib.h
  • 新建C++項目, 在”項目屬性>VC++目錄>包含目錄和庫目錄里”添加上面的lib和include路徑;
  • “項目屬性>連接器>輸入”里添加lua5.3.2.lib
  • OK
#include <stdio.h> #include <string.h>extern "C" { #include <lua.h> #include <lualib.h> #include <lauxlib.h> } int main(int argc, char* argv[]) {lua_State *L = luaL_newstate();luaL_openlibs(L); // 加載Lua通用擴展庫if(luaL_loadfile(L,"test.lua"||lua_pcall(L,0,0,0)) //或luaL_dofile(L,"test.lua")printf("error pcall!: %s\n",lua_tostring(L,-1));// 前面搭建了運行環境,lua代碼寫在了test.lua文件中// ......//lua_close(L);return 0; }

C++調用Lua函數

要在C++中調用lua函數,則有如下函數可以利用:
lua_getglobal()就是從lua中取得函數,壓入棧中;隨后壓入函數的參數;

如在test.lua中有如下代碼:

function he(x,y)return x*y end

則的C++中的調用過程是:

//..... lua_getgloabl(L,"he"); lua_pushnumber(L,5); lua_pushnumber(L,6); // run the lua program // lua_pcall(L,nargs,nresults,0) if(lua_pcall(L,2,1,0) != 0)printf("error pcall!: %s\n",lua_tostring(L,-1)); // if error then push errorinfo in the stack else push reuslts if(!lua_isnumber(L,-1))printf("error return!\n"); int re = (int)lua_tonumber(L,-1);

函數參數、返回值壓棧是正序壓棧;如果有錯誤發生的話, lua_pcall 會捕獲它,然后把單一的值(錯誤信息)壓入堆棧,然后返回錯誤碼。lua_pcall 總是把函數本身和它的參數從棧上移除。


Lua中調用C++函數

  • 要寫一個能讓Lua調用的C函數,就要符合lua_CFunction定義:typedef int (*lua_CFunction) (lua_State *L); //return 返回值的個數
  • 當Lua調用C函數的時候,同樣使用棧來交互。C函數從棧中獲取她的參數,調用結束后將結果放到棧中,并返回放到棧中的結果個數。
  • 這兒有一個重要的概念:用來交互的棧不是全局棧,每一個C函數都有他自己的私有棧。當Lua調用C函數的時候,第一個參數總是在這個私有棧的index=1的位置。
如:函數he // 普通函數static int he(lua_State* L){// 從棧中檢查參數是否合法并讀取參數,int a = luaL_checknumber(L,1);int b = luaL_checknumber(L,2);int re = a*b;// 將運算結果返回棧中供lua使用lua_pushnumber(L,re);return 1;}// 在C++中向lua傳遞table結構的數據// 這里的table是:{{"he"},{"li"}}int TTable(lua_State* L){// 創建大tablelua_newtable(L,1);// 大table的keylua_pushnumber(L,1); // 1為鍵//第一個小tablelua_newtable(L); // 第一個小table的key,valuelua_pushnumber(L,1);lua_pushstring(L,"he");lua_settable(L,-3);//第一個小table的成員結束lua_settable(L,-3);//第二個小table,類似上面的過程lua_pushnumber(L,2); // 2為鍵lua_newtable(L,2);lua_pushnumber(L,1);lua_pushstring(L,"li");lua_settable(L,-3);lua_settable(L,-3)return 1; //1個大table}

在main中可以使用lua_dostring(),lua_loadfile(),lua_pcall(L,0,0,0) 來執行lua代碼:

int main(int argc, char* argv[]) {lua_State *L = luaL_newstate();luaL_openlibs(L); // 加載Lua通用擴展庫// 將he函數注冊成lua的全局函數lua_register(L,"he",he);if(luaL_loadfile(L,"test.lua")/*||lua_pcall(L,0,0,0)*/)printf("error pcall!: %s\n",lua_tostring(L,-1));lua_close(L);return 0; }

.lua文件文間之間的全局變量調用

比如有兩個文件

//a.lua a = 50 local b = 10//h.lua dofile("X:/.../a.lua") //或在同一個目錄下時:doflie("a.lua"),require會更好 print(a,b)

lua中:
h.lua想要調用a.lua中的內容則要在a.lua中運行dofile("X:/.../a.lua")

C++中兩種方法:

  • 如上面所示, 在h.lua中使用dofile(“a.lua”), 文件放同一個目錄;
  • 或在C代碼加載時先用luaL_dofile(L,"a.lua"); 再luaL_dofile(L,"h.lua"); 順序不能變;

引入C模塊到 lua

  • luaL_register
    這個函數接收一些C函數及其名稱,并將這些函數注冊到一個與模塊同名的table中。假設創建一個模塊,其中包含了這個luaglue函數。首先,必須定義這個模塊函數:
static int luaglue(lua_state *L) { }

然后,聲明一個數組,其中包含模塊中所有函數及名稱。這個數組元素的類型為luaL_Reg結構,該結構有兩個字段,一個字符串和一個函數指針:

static const struct luaL_Reg mylib[] = { {"dir",l_dir}, {NULL,NULL}//結尾 };

最后,聲明一個主函數,其中用到了luaL_register:

int luaopen_mylib(lua_State *L) {luaL_register(L,"mylib",mylib);return 1; }

其中luaL_register原型為:

void luaL_register (lua_State *L,const char *libname,const luaL_Reg *l);

luaL_register根據給定的名稱(“mylib”)創建(或復用)一個table,并用數組mylib中的信息填充這個table。在luaL_Register返回時,會將這個table留在棧中。最后,luaopen_mylib函數返回1,表示將這個table返回給Lua。

打開一個庫,當libname為null時,該函數注冊所有在luaL_Reg上的函數,不為null時,該函數會創建一個table,根據libname注冊不與libname關聯的函數。

  • 當寫完c模塊后,必須將其鏈接到解釋器。如果Lua解釋器支持動態鏈接的話,那么最簡便的方法是使用動態鏈接機制。在這種情況中,必須將c代碼編譯成動態鏈接庫,并將這個庫放入C路徑(LUA_CPATH)中。然后,便可以用require從Lua中加載這個模塊:
require "mylib"

這個調用會將動態庫mylib鏈接到Lua,并會尋找luaopen_mylib函數,將其注冊為一個Lua函數,然后調用它以打開模塊。
如果解釋器不支持動態鏈接,那么就必須用新的模塊來重新編譯Lua。此外,還需要以某種方式來告訴解釋器,它應在打開一個新狀態的同時打開這個模塊。最簡單的做法是,將luaopen_mylib加到luaL_openlibs會打開的標準庫列表中,這個列表在文件linit.c中。
從C++程序員的觀點來看,Lua像一個“黑盒子”,為一些服務處理命令和調用。Lua通常作為最上層接口直接和程序使用者和游戲玩家打交道,在核心程序處理之前接受并響應輸入。


lua5.3 C++注冊函數或模塊到lua

  • 上面的那個luaL_register函數在lua5.2以后就沒有用了,所以一直在找5.2以后版本的用法, 網上找了半天都沒有指出重點,最后在下面的網站上找到;
    http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/
    結合下面兩篇介紹后這里給出一些理解:
    http://www.linuxidc.com/Linux/2014-05/102528p2.htm
    http://blog.163.com/cqit_jsj/blog/static/65127220127251231881/
//要注冊的lua里的C++函數的寫法這里就不說了,隨便寫一個 static int f(lua_State* L) {printf("hello\n");return 0; } // .... 還可以繼續添加 //注冊函數數組 const luaL_Reg mylib[] = {{"myf",f},//{//可以繼續添加},{NULL,NULL} } //定義一個庫打開函數 static luaopen_mylib(lua_State* L) {//lua5.1 是luaL_register(L,"mylib",mylib)來完成// lua5.2以上是lua_newlib(L,mylib);//或者等效為下面luaL_newlibtable(L,mylib);lubL_setfuncs(L,func,0);return 1; } //如果有多個庫可以在用個庫數組來進行注冊如下 // 可不用 const luaL_Reg lualibs[]= {{"mylib",luaopen_func}, //打開庫函數{/*其它庫*/},{NULL,NULL}, }

到這里,我們可以選擇去將庫導出為.dll來在lua中調用,這個網上好多資料,在lua中要用local mylib = require "mylib"來獲取.dll文件, 參考
http://blog.csdn.net/ljhjason/article/details/28860633
這里選擇不導出為.dll所以進行如下操作:

int main{lua_State* L = luaL_newstate();luaL_openlibs(L);// 打開自己的庫如果用了lublibs庫數組則用循環打開luaL_requiref(L,"mylib",luaopen_mylib,1);lua_pop(L,1);luaL_dofile("xxx.lua");.... }

注冊C++類到lua

http://blog.csdn.net/siddontang/article/details/2316547


C++ struct對應到lua table


// 壓入表的鍵值對函數(沒有進行棧檢測)
inline void PushTableKV(lua_State* L, const char* k, int v)
{
lua_pushstring(L,k);
lua_pushnumber(L,v);
lua_settable(L,-3);
}
// 使用時候
{
lua_newtable(L)
PushTableKV(L,"v1",10);
....
}

總結

以上是生活随笔為你收集整理的Lua5.3 与C交互学习(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。