加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

LUA与C++交互第一篇

发布时间:2020-12-14 22:11:45 所属栏目:大数据 来源:网络整理
导读:?到公司已经两个周了,学习Lua已经开始在项目中使用,但是由于使用的lua函数基本上都是公司在上面进行了一次封装的,没有源代码对两种语言的交互详情还是不甚了解。如:如果向LUA注册一个对象给LUA使用,如何调用LUA中函数这些在公司的SDK看来就是一个简单的

?到公司已经两个周了,学习Lua已经开始在项目中使用,但是由于使用的lua函数基本上都是公司在上面进行了一次封装的,没有源代码对两种语言的交互详情还是不甚了解。如:如果向LUA注册一个对象给LUA使用,如何调用LUA中函数这些在公司的SDK看来就是一个简单的RegisterObject对象的几个属性进行填写就行了。

? ? 今天主要是对在Lua中如何调用C++函数和在C++中如何调用Lua函数进行学习。

在LUA中要调用C++函数,那就要在C++中对Lua进行注册,如何注册呢?需要一个宏来完成功能,就是lua_register(L,"add",add),该宏对应的是两个函数,一个是lua_pushcfunction(L,f),lua_setglobal(L,n);可以看出是先对函数进行压栈、然后给函数设置一个在lua中的调用名称,注意此处的n不是表示一个整数什么的,是name的意思,表示函数的注册名。而此处lua_setglobal也是一个宏,

 #define lua_setglobal(L,s)   lua_setfield(L,LUA_GLOBALSINDEX,s)
可以看出其实lua_setglobal只是lua_setfield的一个特例,因为LUA_GLOBALSINDEX是一直存在的,所以使用干函数来简单操作,当然如果我们要注册的函数不注册到全局的,而是在其他某个我们定义的表内可访问,那就要调用lua_setfield函数了。说到这个话题,设计到的函数就会越来越多,比如lua_getglobal与lua_setglobal对于,lua_getfield与lua_getfield对应,我们用到的时候再解释,不用到时就不说了。
  上面提到了使用lua_register函数进行注册,这里要强调的是该函数对注册的函数原型是有要求的,不是任何函数都可以注册,函数原型如下:
int (func*)(lua_State* L);我们应该能够理解,LUA和C++的交互通过栈来进行传参,因此只需要给一个参数lua_State表当前操作栈就行了,至于该函数有几个参数,返回值这些在func函数中去处理就好了,该函数返回值表示C++函数会向栈中放多少个值,而至于需要几个参数可以通过lua_tostring、lua_tointeger等函数通过传入栈中的序号来获取。由于注册函数原型固定了,但我们在写C++函数的时候不可能代码长短什么的都往该函数中塞,在实际中我们常常是只使用该函数来获取从LUA读取参数和返回参数,所以该函数一般是这样的形式:
int funcname(lua_State* L)
{
    //此处可以做数据类型检查这些
    ..
    //取值
    arg1 = lua_tostring(L,-1);
    arg2 = lua_tostring(L,-2);
    //调用真正的函数
    dosomething_function
   //进行参数压栈等也可以再上面调用的函数中压栈
   return n;//此处的n是C++向栈中压入的参数个数,如果和压入栈个数不一致,可能导致栈失衡
}
注册函数来说就上面几个步骤而已,比起注册C++类来说简单得多,注册C++类现在我也还没有掌握,在此处就不说了,下面说的是我们注册了C++函数现在该到LUA中去调用了,现在在test.lua文件中添加这样一个函数
function lua_add(a,b)
   return add(a,255)">end
现在如果在命令行执行该文件应该会失败,因为我上面注册的C++函数不是注册成一个动态库,我是直接在控制台可执行文件中写的,因此我就需要在
C++中来调用该lua_add函数了。C++中需要先知道有lua_add这样一个函数,需要先使用luaL_dofile(test.lua)来加载该文件,加载进去后该函数就存在于全局表中了,于是使用lua_getglobal函数来从表中获取函数地址lua_getglobal(L,"lua_add"),该函数是在全局表中查找lua_add函数并把它压到栈顶,到这里刚开始学习的时候会很疑惑,当初我看lua中很多函数介绍的时候就觉得很不解,很多函数就是对栈操作,单独看一个函数实在看不出想达到什么目的,但和其他函数配合使用功能就强大了,所以需要对lua中这些对栈操作的函数都有一个认识,才能够组合出自己需要的功能来。前面说把函数找到压栈了,下面就是要调用函数,调用函数前需要传参数,如何传?还是把参数放到栈中、如果我们需要给函数传两个参数,把连个参数压栈,使用函数lua_pushinteger(L,4)表示向栈中压入一个整数4,其他类型如lua_pushstring,lua_pushlstring等很多。参数也进栈了,下面才是开始真正调用,如何调?lua提供的函数lua_pcall来调用,该函数第一个参数为lua_State表示当前的栈吧,第二个参数表示要调用函数的参数个数,第三个表示被调用函数的返回值个数,这个不要想C++中函数只有一个返回值,这是表示我们要向lua中返回多少个值;第四个参数表示错误处理函数在栈上的索引,为0表示没有错误处理函数,和lua_pcall一样用于调用栈中函数的函数有lua_call和lua_cpcall等,这里不仔细介绍。在上面的函数调用中,由于返回值存在与栈中,在取回返回值后,需要调用lua_pop(L)对栈进行清空。
下面是一个测试代码:
 
 
  1. #include?<stdio.h>??
  2. ??
  3. extern?"C"??
  4. {??
  5. ????#include?<lua.h>??
  6. ????#include?<lualib.h>??
  7. ????#include?<lauxlib.h>??
  8. }??
  9. ??
  10. #include?<string>??
  11. using?namespace?std;??
  12. int?add(lua_State*?L)??
  13. ????int?a?=?lua_tointeger(L,1);//取得函数参数??
  14. ????int?b?=?lua_tointeger(L,2);??
  15. ????lua_pushinteger(L,a+b);//入栈返回值??
  16. ????return?1;//1表示压入栈数据个数??
  17. struct?luaL_Reg?luaCppReg[]?=//可以使用该结构体一次注册多个函数,则需要调用luaL_register函数,此处没有使用??
  18. ????{"add",add},??
  19. ????{NULL,NULL}??
  20. };??
  21. int?_tmain(int?argc,?_TCHAR*?argv[])??
  22. {??
  23. char?buff[256];??
  24. int?error;'??
  25. ????lua_State?*L?=?luaL_newstate();??/*?opens?Lua,由于我使用的是lua5.2版本,lua_open函数不存在了?*/??
  26. ????luaopen_base(L);?????????/*?opens?the?basic?library?这些是在引入一些库,就如如果add函数在编译成dll后如果在lua中要使用需要require?“动态库名"一样*/??
  27. ????luaopen_table(L);????????/*?opens?the?table?library这些库是加在这里只是测试?*/??
  28. ????luaopen_io(L);???????????/*?opens?the?I/O?library?*/??
  29. ????luaopen_string(L);???????/*?opens?the?string?lib.?*/??
  30. ????luaopen_math(L);?????????/*?opens?the?math?lib.?*/??
  31. ??????
  32. ????lua_register(L,"add",add);//注册add函数,好像还可以使用luaL_register函数注册,该函数使用结构体的方式??
  33. ????luaL_dofile(L,"test.lua");//加载lua文件,回将里面的函数加载到全局表中??
  34. ????lua_getglobal(L,"lua_add");//查找lua_add函数,并压入栈底??
  35. //函数参数1??
  36. ????lua_pushinteger(L,5);//函数参数2??
  37. ????lua_pcall(L,2,1,0);//调用lua_add函数,同时会对lua_add及两个参加进行出栈操作,并压入返回值??
  38. int?result?=?lua_tointeger(L,-1);//从栈中取回返回值??
  39. ????lua_pop(L,1);//清栈,由于当前只有一个返回值??
  40. ????printf("result?=?%d",result);??
  41. ????lua_close(L);//关闭lua环境??
  42. ????return?0;??
  43. }??

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读