C++ 调用 lua 函数

来源:互联网 发布:网络监控软件客户端 编辑:程序博客网 时间:2024/06/06 11:45

在上一节中,讲述了如何产生一个lua的静态链接库,在这一节,将讲述简单使用lua5.1.lib的过程。

     首先先建立一个新的win32 Console Application,在新工程里,为了美观,我将默认生成的文件夹删除,建立了include和src两个文件夹。在根目录下建立了三个文件夹:lib,script,include。

             

      将上节生成的lua5.1.lib放入lib文件夹,将lua源码中的lauxlib.h,lua.h,luaconf.h,lualib.h拷贝到include文件夹。

      在VS上,将根目录中include中的四个头文件加载到include中。在src中建立AMLua.h,AMLua.cpp,AMMain.cpp三个文件。

      

       下面在项目属性页进行一些必要设置,包含依赖项,库路径等。

        C/C++ -- General -- Additional Include Directories:..\include

        Linker -- General -- Additional Library Directories:..\lib

        Linker -- Input -- Additional Dependencies:lua5.1.lib

        另外,检查C/C++ -- General -- Code Generation -- Runtime Library,是否与第一节编译时所记录的Multi-threaded Debug Dll(/MDd)相同,如果不同,请修改成相同的模式。

        -----------------------------------------------分割线-----------------------------------------------

        使用lua的配置以及好了,下面开始写代码试试。

        首先写一个简单的脚本,在script文件夹中建立sample.lua,里边填上: 

       

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">function luaAdd(x, y)  
  2.      return x + y  
  3. end</span>  

        (吐槽下,居然没有lua的模板,只好使用C++的)

       在AMMain.cpp中填上以下代码:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">#include <iostream>  
  2.   
  3. extern "C"  
  4. {  
  5. #include "lua.h"  
  6. #include "lualib.h"  
  7. #include "lauxlib.h"  
  8. };  
  9.   
  10. int main(int argc, char** argv)  
  11. {  
  12.     // 初始化一个栈   
  13.     lua_State* L = luaL_newstate();  
  14.   
  15.     // 加载lua库  
  16.     luaL_openlibs(L);  
  17.   
  18.     // 加载lua文件  
  19.     luaL_dofile(L, "..\\script\\sample.lua");  
  20.   
  21.     // 加载函数  
  22.     lua_getglobal(L, "luaAdd");  
  23.   
  24.     // 传入参数  
  25.     lua_pushnumber(L, 20);  
  26.     lua_pushnumber(L, 40);  
  27.   
  28.     // 调用函数,运行  
  29.     lua_pcall(L, 2, 1, 0);  
  30.     int nSum = 0;  
  31.     if(lua_isnumber(L, -1) == 1)  
  32.     {  
  33.         nSum = lua_tonumber(L, -1);  
  34.     }  
  35.   
  36.     std::cout<< "The Sum:\t"<< nSum << std::endl;  
  37.     std::cout<< "please wait..." << std::endl;  
  38.     getchar();  
  39.   
  40.     return 0;  
  41. }</span>  

   运行查看结果:输出60;      

下面对AMMain.cpp进行修改,对lua提供的函数进行简单封装:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">#include <iostream>  
  2.   
  3. extern "C"  
  4. {  
  5. #include "lua.h"  
  6. #include "lualib.h"  
  7. #include "lauxlib.h"  
  8. };  
  9.   
  10. lua_State* L;  
  11. int luaAdd(int x, int y);  
  12.   
  13. int main(int argc, char** argv)  
  14. {  
  15.     // 初始化一个栈   
  16.     L = luaL_newstate();  
  17.   
  18.     // 加载lua库  
  19.     luaL_openlibs(L);  
  20.   
  21.     // 加载lua文件  
  22.     luaL_dofile(L, "..\\script\\sample.lua");  
  23.   
  24.     int nSum = luaAdd(20, 60);  
  25.   
  26.     std::cout<< "The Sum:\t"<< nSum << std::endl;  
  27.     std::cout<< "please wait..." << std::endl;  
  28.     getchar();  
  29.   
  30.     return 0;  
  31. }  
  32.   
  33. int luaAdd(int x, int y)  
  34. {  
  35.     // 加载函数  
  36.     lua_getglobal(L, "luaAdd");  
  37.   
  38.     // 传入参数  
  39.     lua_pushnumber(L, x);  
  40.     lua_pushnumber(L, y);  
  41.   
  42.     // 调用函数,运行  
  43.     lua_pcall(L, 2, 1, 0);  
  44.     int nSum = 0;  
  45.     if(lua_isnumber(L, -1) == 1)  
  46.     {  
  47.         nSum = lua_tonumber(L, -1);  
  48.     }  
  49.     return nSum;  
  50. }</span>  

       在本节展示了用在C++上调用lua脚本函数。在下一节,将介绍一个第三方库,我们现在C++上写函数,然后在lua中调用此函数,最后在C++中调用这个lua函数。(感觉挺绕的)

-------------------------------------------------------------------------------------------------------------------------

lua_call,和该函数相似的函数分别是lua_pcall和lua_cpcall.这些函数的目的就是让我们能够执行压入栈中的函数,该函数可能是lua中定义的函数,可能是C++重定义的函数,当然我们一般是用来执行lua中执行的函数,C++中定义的基本上可以直接调用的。函数原型:

void lua_call (lua_State *L, int nargs, int nresults);
L是执行环境,可以理解为当前栈,nargs参数个数,nresults返回值个数。lua_pcall和该函数区别是多一个参数,用于发生错误处理时的代码返回。
void lua_pcall(lua_State *L,int nargs, int nresults,int nerrfunc);lua_cpcall则又多一个用于传递用户自定义的数据结构的指针
void lua_pcall(lua_State *L,int nargs, int nresults,int nerrfunc,void* ud)
对于函数的使用场景,在网上有一个网友的说明是这样的:

lua_call的运行是无保护的,他与lua_pcall相似,但是在错误发生的时候她抛出错误而不是返回错误代码。当你在应用程序中写主流程的代码时,不应该使用lua_call,因为你应该捕捉任何可能发生的错误。当你写一个函数的代码时,使用lua_call是比较好的想法,如果有错误发生,把错误留给关心她的人去处理.

结论:写应用程序主流程代码用lua_pcall写C Native Function代码时用lua_call,与之类似的还有luaL_checkxxx

下面是一个在文档中列举的一个例子:

The following example shows how the host program can do the equivalent to this Lua code:

     a = f("how", t.x, 14)

Here it is in C:

[cpp] view plaincopy
  1. lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* function to be called */  
  2. lua_pushstring(L, "how");                        /* 1st argument */  
  3. lua_getfield(L, LUA_GLOBALSINDEX, "t");   /* table to be indexed */  
  4. lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */  
  5. lua_remove(L, -2);                  /* remove 't' from the stack */  
  6. lua_pushinteger(L, 14);                          /* 3rd argument */  
  7. lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */  
  8. lua_setfield(L, LUA_GLOBALSINDEX, "a");        /* set global 'a' */  
在上面的例子除了描述了lua_call的使用外,还对lua_getfield的使用有一定的参考价值。特别是学习如何在一个表中获取他的值。
在上面的例子中,可能再调用lua_getfield时就会忘记调用lua_remove,当然这是我想象自己使用时会犯下的错。lua_getfield函数功能是从指定表中取出指定元素的值并压栈。上面获取t.x的值的过程就是先调用
 lua_getfield(L, LUA_GLOBALSINDEX, "t"); 从全局表中获取t的值,然而t本身是一个表,现在栈顶的值是t表。于是再一次
 lua_getfield(L, -1, "x"); 从t中取出x的值放到栈上,-1表示栈顶。那该函数执行完成后t的位置由-1就变成-2了,所以下面一句
lua_remove索引的是-2,必须把t给remove掉,否则栈中就是4个参数了。上面的最后一句lua_setfield的目的是把返回值取回赋给全局变量a,因为在lua_call执行完成后,栈顶的就是返回值了。




0 0
原创粉丝点击