1.C调用Lua函数
(1) 首先要进行Lua的初始化,这个主要是lua_open和luaL_openlibs函数
(2)然后是解析并编译lua的代码,这个主要是luaL_dofile函数
(3) 解析好之后使用lua_getglobal指明要调用的lua函数
(4) 如果有lua函数的参数,通过使用lua_pushstring函数传递参数
(5) 最后调用lua_pcall进行lua函数的调用
(6) 调用完成之后采用lua_tonumber类函数可以获取到函数的返回结果
2.Lua调用C函数
(1) 在Lua中调用C的函数,该函数必须进行注册,这个通过lua_register这个函数来完成
(2) 在Lua中调用注册的函数,会调用上面注册的函数(类似于回调),所有的处理在这个函数里面
(3) 这个函数里面可以使用lua_tostring类函数来获取函数的参数
(4) 如果有返回值,通过lua_pushnumber这个函数来返回。
3.例子
1 extern "C" { 2 #include "lua.h" 3 #include "lualib.h" 4 #include "lauxlib.h" 5 } 6 7 #include <iostream> 8 #include <string> 9 using namespace std; 10 11 int main() 12 { 13 //Lua示例代码 14 char *szLua_code = 15 "r = string.gsub(c_Str, c_Mode, c_Tag) --宿主给的变量 " 16 "u = string.upper(r)"; 17 //Lua的字符串模式 18 char *szMode = "(%w+)%s*=%s*(%w+)"; 19 //要处理的字符串 20 char *szStr = "key1 = value1 key2 = value2"; 21 //目标字符串模式 22 char *szTag = "<%1>%2</%1>"; 23 24 lua_State *L = luaL_newstate(); 25 luaL_openlibs(L); 26 27 //把一个数据送给Lua 28 lua_pushstring(L, szMode); 29 lua_setglobal(L, "c_Mode"); 30 lua_pushstring(L, szTag); 31 lua_setglobal(L, "c_Tag"); 32 lua_pushstring(L, szStr); 33 lua_setglobal(L, "c_Str"); 34 35 //执行 36 bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code), 37 "demo") || lua_pcall(L, 0, 0, 0); 38 if(err) 39 { 40 //如果错误,显示 41 cerr << lua_tostring(L, -1); 42 //弹出栈顶的这个错误信息 43 lua_pop(L, 1); 44 } 45 else 46 { 47 //Lua执行后取得全局变量的值 48 lua_getglobal(L, "r"); 49 cout << "r = " << lua_tostring(L,-1) << endl; 50 lua_pop(L, 1); 51 52 lua_getglobal(L, "u"); 53 cout << "u = " << lua_tostring(L,-1) << endl; 54 lua_pop(L, 1); 55 } 56 lua_close(L); 57 return 0; 58 }
这段代码把字符串中的key=value字符串全部转换成XML格式<key>value</key>,在这个例子中,C++程序通过调用lua_pushstring把C字符串压入栈顶,lua_setglobal的作用是把栈顶的数据传到Lua环境中作为全局变量。执行代码完成后,使用lua_getglobal从Lua环境中取得全局变量压入栈顶,然后使用lua_tostring把栈顶的数据转成字符串。由于lua_tostring本身没有出栈功能,所以为了平衡(即调用前与调用后栈里的数据量不变),使用lua_pop弹出由lua_setglobal压入的数据。
从上面的例子可以看出,C++和Lua之间一直围绕着栈在转,可见栈是极为重要的。有必要列出一些Lua C API中的主要栈操作先,它们的作用直接可以从函数名中看出。
3.1 压入元素到栈里
1 void lua_pushnil (lua_State *L); 2 void lua_pushboolean (lua_State *L, int bool); 3 void lua_pushnumber (lua_State *L, double n); 4 void lua_pushlstring (lua_State *L, const char *s, size_t length); 5 void lua_pushstring (lua_State *L, const char *s); 6 void lua_pushcfunction (lua_State *L, lua_CFunction fn);
3.2 查询栈里的元素
1 lua_isnil (lua_State *L, int index); 2 lua_isboolean (lua_State *L, int index); 3 int lua_isnumber (lua_State *L, int index); 4 int lua_isstring (lua_State *L, int index); 5 int lua_isfunction (lua_State *L, int index); 6 int lua_istable (lua_State *L, int index); 7 int lua_isuserdata (lua_State *L, int index); 8 lua_islightuserdata (lua_State *L, int index); 9 lua_isthread (lua_State *L, int index);
3.3 转换栈里的元素
1 int lua_toboolean (lua_State *L, int index); 2 double lua_tonumber (lua_State *L, int index); 3 const char * lua_tostring (lua_State *L, int index); 4 const char * lua_tolstring (lua_State *L, int idx, size_t *len); 5 size_t lua_strlen (lua_State *L, int index); 6 lua_CFunction lua_tocfunction (lua_State *L, int idx); 7 void * lua_touserdata (lua_State *L, int idx); 8 lua_State * lua_tothread (lua_State *L, int idx);
3.4 Lua栈的维护
1 int lua_gettop (lua_State *L); //取得栈顶元素的索引,即栈中元素的个数 2 void lua_settop (lua_State *L, int index); //设置栈顶索引,即设置栈中元素的个数,如果index<0,则从栈顶往下数,下同 3 void lua_pushvalue (lua_State *L, int index); //把栈中指定索引的元素复制一份到栈顶 4 void lua_remove (lua_State *L, int index); //删除指定索引的元素 5 void lua_insert (lua_State *L, int index); //移动栈顶元素到指定索引的位置,栈中数目没有改变 6 void lua_replace (lua_State *L, int index); //从栈顶弹出元素值并将其设置到指定索引位置,栈中的数目减一 7 int lua_checkstack (lua_State *L, int extra); //确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈。 8 int lua_pop(L,n); //从栈顶弹出n个元素,它是一个lua_settop的包装:#define lua_pop(L,n) lua_settop(L, -(n)-1)
3.5 表的操作
上面的列表中并没有lua_pushtable和lua_totable,那么怎样取得或设置Lua中的table数据呢?
在Lua中,table是一个很重要的数据类型,在table中不仅可以象C中的数据一样放一组数据,还可以象map一样以key=value的方式存放数据,如Lua代码中的:
tb = {"abc",12,true,x=10,y=20,z=30}
前三个数据可以用tb[1]~tb[3]取得,而后三个数据通过tb.x, tb.y, tb.z取得,尽管看起来很牛叉,不过剥开神奇的外衣,实际上Lua的table中,所有的数据都是以key=value的形式存放的,这句Lua代码也可以写成:
tb = {[1]="abc", [2]=12, [3] = true, ["x"]=10, ["y"]=20, ["z"]=30}
它的形式就是[key]=value,所谓的tb.x只是tb["x"]的语法糖而已,如果愿意,也可以用tb["x"]取得这个数据10。我们把上面的例子改成使用表的
1 ... 2 int main() 3 { 4 //Lua示例代码,使用table 5 char *szLua_code = 6 "x = {} --用于存放结果的table " 7 "x[1],x[2] = string.gsub(c.Str, c.Mode, c.Tag) --x[1]里是结果,x[2]里是替换次数 " 8 "x.u = string.upper(x[1])"; 9 //Lua的字符串模式 10 char *szMode = "(%w+)%s*=%s*(%w+)"; 11 //要处理的字符串 12 char *szStr = "key1 = value1 key2 = value2"; 13 //目标字符串模式 14 char *szTag = "<%1>%2</%1>"; 15 16 lua_State *L = luaL_newstate(); 17 luaL_openlibs(L); 18 19 //把一个tabele送给Lua 20 lua_newtable(L); //新建一个table并压入栈顶 21 lua_pushstring(L, "Mode");// key 22 lua_pushstring(L, szMode);// value 23 //设置newtable[Mode]=szMode 24 //由于上面两次压栈,现在table元素排在栈顶往下数第三的位置 25 lua_settable(L, -3); 26 //lua_settable会自己弹出上面压入的key和value 27 28 lua_pushstring(L, "Tag");// key 29 lua_pushstring(L, szTag);// value 30 lua_settable(L, -3); //设置newtable[Tag]=szTag 31 32 lua_pushstring(L, "Str");// key 33 lua_pushstring(L, szStr);// value 34 lua_settable(L, -3); //设置newtable[Str]=szStr 35 36 lua_setglobal(L,"c"); //将栈顶元素(newtable)置为Lua中的全局变量c 37 38 //执行 39 bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code), 40 "demo") || lua_pcall(L, 0, 0, 0); 41 if(err) 42 { 43 //如果错误,显示 44 cerr << lua_tostring(L, -1); 45 //弹出栈顶的这个错误信息 46 lua_pop(L, 1); 47 } 48 else 49 { 50 //Lua执行后取得全局变量的值 51 lua_getglobal(L, "x"); 52 53 //这个x应该是个table 54 if(lua_istable(L,-1)) 55 { 56 //取得x.u,即x["u"] 57 lua_pushstring(L,"u"); //key 58 //由于这次压栈,x处于栈顶第二位置 59 lua_gettable(L,-2); 60 //lua_gettable会弹出上面压入的key,然后把对应的value压入 61 //取得数据,然后从栈中弹出这个value 62 cout << "x.u = " << lua_tostring(L,-1) << endl; 63 lua_pop(L, 1); 64 65 //取得x[1]和x[2] 66 for(int i=1; i<=2; i++) 67 { 68 //除了key是数字外,与上面的没什么区别 69 lua_pushnumber(L,i); 70 lua_gettable(L,-2); 71 cout << "x[" << i <<"] = " << lua_tostring(L,-1) << endl; 72 lua_pop(L, 1); 73 } 74 } 75 76 //弹出栈顶的x 77 lua_pop(L, 1); 78 } 79 lua_close(L); 80 return 0; 81 }
本例中用到的新Lua C API是:
1 void lua_newtable (lua_State *L); //新建一个空的table并压入栈顶。 2 void lua_settable (lua_State *L, int idx); //lua_settable以table在栈中的索引作为参数,并将栈顶的key和value出栈,用这两个值修改table。 3 void lua_gettable (lua_State *L, int idx); //lua_gettable以table在栈中的索引作为参数,弹出栈顶的元素作为key,返回与key对应的value并压入栈顶。最后,Lua告别针对table提供了存取函数 4 void lua_rawgeti (lua_State *L, int idx, int n); //取得table[n]并放到栈顶,上例中69-70行的lua_pushnumber(L,i);lua_gettable(L,-2);可以用lua_rawgeti(L,-1)代替。 5 lua_getfield (lua_State *L, int idx, const char *k); //取得table.k并放到栈顶,上例中57-59行的lua_pushstring(L,"u");lua_gettable(L,-2);可以替换成lua_getfield(L,-1,"u")。 6 void lua_setfield (lua_State *L, int idx, const char *k); //把栈顶的数据作为value放入table.k中,上例中的形如lua_pushstring(L, "key");lua_pushstring(L, value);lua_settable(L,-3);可以改成lua_pushstring(L,value);lua_setfield(L,-2,"key");的形式。 7 void lua_rawseti (lua_State *L, int idx, int n); //把栈顶的数据作为value放入table[n]中