打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
lua跟c++/c交互

lua跟c++/c交互

lua和c++/c交互

好久没有写文章了,前些天在我的资源里面上传了一个有关lua和c++/c交互(一下文章中都用c++代替)问题的文档,小伙伴们说有点难懂,这里我在详细描述一下吧!

看文章之前小伙伴要弄清楚table,metaTable概念。说起metaTable,我忍不住想多说几句了。

 

既然有了table,为什么还要metaTable呢?假设现在你有一个yourtable,yourtable里面有一个fun函数.本身应该这样调用yourtable.funName(point,1,0),但被别人恶意写成了youtable.funName(io.stdion,1,0) 造成 memory corruption .这时你会想到在c语言中的funName检测指针有效性,那你怎么检测指针是有效的呢?所有才想到把指针和某个变量名一一对应,凡是对指针的调用都通过变量名来检测变量是否存在,聪明的你会想到metaTable存在的价值了吧。说白了,metatable就是一个在系统中注册了一个名字的的特殊table

metaTable,userdata,object point他们之间有什么关系呢?

void * luaL_checkudata(lua_State *L, int index, const char* name):

this function checks whether the object at the given stack position is a userdata with a metatable that matches the given name。其实lua传到c里面的对象指针都可以看做是一个userdata指针,userdata本身就是一个特殊的table,说他特殊是因为具有__index,__gc这两个key值,但不能创建别的key。userdata还有一个特殊的key,这个key可以指向metable。我可能理解的不对,欢迎指正。

如何在C中申请一个metatable或者table,在lua中直接使用?

struct luaL_reg arraylib_reg_m[]=

{

{"getName", getNameInc},

{NULL,NULL},

}

luaL_newmetatable(pLua,"selfTable");

lua_pushstring(pLua,"__index");

lua_pushvalue(pLua,-2);

lua_setTable(pLua,-3);//此时selfTableObject.__index = luaL_getmetatable(pLua,"selfTable");操作之后,栈中只有先前创建的table指针

luaL_openlib(pLua,NULL,arraylib_reg,0);

此时在lua中就可以pLua:getName(roleId);记得在c中把getNameInc函数实现

 

看文章的始终,都要明白c++和lua交互是通过堆栈协议实现的。堆栈协议是什么呢,不要急,下文会有答案的。

先来了解几个lua api的用法:

   lua_getglobal(lua_State *L, string funNameInLua);//调用lua函数之前把要调用的名字放到栈中

   lua_push*(lua_State *L, void);//在栈中放入调用参数

   lua_pcall(lua_State *L, int param_num,int return_para_num,0)://在c中调用lua

   void *lua_newuserdata(lua_State *L, size_t size): //申请一块内存,并且把内存指针放到栈顶

 

再熬述一个知识点,在lua api中的两个关键字:

  __index:当table中找不到某个成员时,会把这个键对应的值当做metatable;例如pUser:getName(roleId)[实际上是pUser.getName(pUser,roleId)的缩写],由于pUser是userdata,上面说了

userdata是一个特殊的table,table操作不存在的key时会访问index,userdata本身就没有键,所以直接访问__index对应的值,__index对应的值又是一个在c中注册了的table,则操作变成selfTableObject.getName(pUser,roleId).selfTableObject上面是一个注册了的table,所以就正常访问到了c中的函数

  __gc:垃圾回收元函数,当lua回收table是就会调用它 

 

到此,应该你就了解了lua调用c的全部机制以及详细过程。下文可看可不看。

再纠正一个观点,在lua中调用c中的对象函数,如果不了解的lua api机制或者看过曾经某个大神的代码pUser:GetName()/table.GetName(pUser)//在lua中获取c++中演员对象pUser的name。你肯定会想我是不是只要和c++中使用同一个指针值,在C++中定义一个CUser类,就直接能实现调用操作了?其实不是的,首先lua中不可能知道pUser指针指向的是哪个类,它只知道它指向的是一块未知的内存。怎么实现调用操作呢,这时候metable上场了。不多说,看下面的C++代码:

  看metable相关的函数一个:

    static int newarray (lua_State *L) {

      CUser* pUser = (pUser*)lua_newuserdata(L, sizeof(CUser));

 

      luaL_getmetatable(L, "CUser.pointTable"); //从系统中取得先前已经创建的名字为 CUser.pointTable的table,对象

      lua_setmetatable(L, -2);把CUser.pointTable作为pUser的metaTable

 

      return 1;  /* new userdatum is already on the stack */

    }

 

  lua_State *pLua = lua_Open();

  luaL_openlibs(pLua);

  luaL_newmetable(pLua, "CUser");

  lua_pushstring(pLua, "__gc");

  lua_pushfunction(pLua, DestoryCuser);

  lua_settable(pLua,-3);//__gc=DestoryCuser,之后会把key和value弹出来

  lua_pushstring(pLua,"__index");

  lua_pushvalue(pLua,-2);

  lua_settable(pLua,-3);//__index=CUser,之后会把栈清空

  //下面重点来了,在CUser table中建立了"getName",getNameInC的映射转化

 //用struct luaL_reg数组实现更简单,直接luaL_openlib(pLue,"selfTable",regFun,0);

  lua_pushstring(pLua,"getName");

  lua_pushcfunction(pLua,getNameInC);//在getNameInC中实现通过pUser指针对自身函数getName的调用

  lua_settable(pLua,-3);

  lua_pop(L,1);

 

  lua_file(pLua,"test.lua")

 好了,就说这么多了。如果还有不明白的,那你直接联系我好了,我竭尽全力的吧!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
lua-users wiki: User Data With Pointer Example
Lua和C的交互说明(函数)
Lua 面向对象实现
Step By Step(Lua元表与元方法)(转)
Lua中__index的用法详解
Lua笔记
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服