注册C函数与类成员函数到lua

lua中调用c函数,我们通常要将c函数转换成相应的注册函数,也就是如下形式

       int function(lua_State *L) {}

可是如果我们每个都函数都这么写,既重复了太多的工作量,又容易出错,所以自然想到了用一层代理来连接注册函数与本来的c函数。于是我们可以这样

       int function(lua_State *L)

       {

              //do something

              return callfun();  //这里callfun()就调用了我们本来的c函数

}

 

可是对于callfun我们怎么实现呢。在c语言里面,我们可以使用函数指针来实现我们的函数功能。如对于函数 int myprint(),我们可以声明一个 int(*fn)() = myprint指针,然后通过fu()调用,这样就跟直接调用myprint()一样了,所以我们考虑callfun函数如下:

template <typename RT>

int callfun(RT (*func)(), lua_State *L, int index )

{

       RT ret = func();   //调用函数,得到返回值

       Push(L, ret);     //将返回值压入lua堆栈

       return 1;

}

 

这里实现的是形如RT fun() 的函数调用,对于有多个参数的情况,我们可以定义不同的callfun函数重载实现,如

 

template <typename RT, typename P1>

int callfun(RT (*func)(P1), ……)

 

这样定义有虽然实现起来比较简单,但是对于参数较多的情况就比较难以书写了,不过对于一般的函数,参数都不可能太多(如果太多了我想应该就要重写该函数了),所以我们就按照这样实现。

 

由于考虑到简易说明,声明要处理的函数类型为 int fun(),既参数为0返回值为int

      

于是我们可以定义我们的代理注册函数如下

       template <typename Func>

int registry_function(lua_State *L);

现在我们需要做的就是怎样把我们的函数指针在代理注册里面传给callfun,这里我们需要用到一些lua的实现方法,当lua在把c函数压入堆栈的时候,会把参数存储到upvalue里面,而我们会把registry_function压入堆栈,所以很自然的我们将把upvalue的第一个值作为函数指针的值。而对于函数指针来说,在lua里面就是一个userdata,所以我们可以这样实现:

template <typename Func>

int registry_function(lua_State *L)

{

       //取出函数指针

unsigned char* buffer = (unsigned char*)lua_touserdata(L, lua_upvalueindex(1));

     //调用函数

return callFunc(*(Func*)(buffer), L, 1);

}

 

下面我们的问题就在于怎么样把函数指针放入upvalue中以及将我们的代理注册函数注册进lua,我们定义如下函数:

 

template <typename Func>

void lua_pushdirectclosure(lua_State *L, Func func, unsigned int nupvalues)

{

     //创建userdata并把func指针的值拷贝进去

     unsigned char* buffer = (unsigned char*)lua_newuserdata(L, sizeof(func));

     memcpy(buffer, &func, sizeof(func));

 

     lua_pushcclosure(L, registry_function <Func>, nupvalues + 1);

}

 

     首先我们创建一个userdata并把函数指针赋值给它,然后将registry_function注册给lua,这时由于userdata为第一个参数,所以我们可以在调用registry_function的时候取出使用。在通过call函数调用原本的c函数。

 

     为了考虑到方便实现,我们定义一个宏:

     #define lua_directregistry_function(L, func) /

     lua_pushstring(L, #func); /

     lua_pushdirectclosure(L, func, 0); /

     lua_settable(L, LUA_GLOBALSINDEX);

    

     在程序里面,假设我们的函数为 int myprint() {}

     则我们在c语言里面使用如下

     lua_directregistry_function(L, myprint);

     然后在lua里面就可以通过myprint()调用该函数了。

 

     以上是实现的在lua里面对不同类型的c语言函数进行封装调用,其实重点就是通过改函数的函数指针来进行操作,其实对于类里面的成员函数,我们同样可以注册进入lua,然后像一般函数进行调用。

     对于类的成员函数,我们需要类的成员函数指针来操作,假设有一个类

 

     class A

     {

     public:

         int test();  

};

 

我们可以这样定义test的函数指针

 

int (A::*fun)();

fun = &A::test;

 

使用的时候我们可以这样:

 

A a;

(a.*fun)();

 

对以对我们来说,实现类的成员函数注册重点就是操作类的成员函数的函数指针。我们仍然把该函数指针存放到upvalue的第一个值处。

首先是call函数声明,由于有了类,所以如下:

 

template <typename Cla, typename RT>

int callfunc(Cla &cla, RT (Cla::*func)(), )

{

     RT ret = (cla.*func)();

     //do something

}

 

然后就是把成员函数指针的值拷入userdata中:

     unsigned char* buffer = (unsigned char*)lua_newuserdata(L, sizeof(Cla) + sizeof(func));

     memcpy(buffer, &cla, sizeof(Cla));

memcpy(buffer + sizeof(Cla), &func, sizeof(func));

 

     而在我们的代理注册函数里面,调用call函数如下:

     callfunc(*(Cla*)buffer, *(Func*)(buffer + sizeof(Cla)), L, 1);

 

     由于对于一般的类成员函数来说(静态除外),我们的调用方式是class.function(),所以在userdata中我们需要保存两个值,一个是该类的地址,一个是类的函数的地址。

 

     这样我么就可以把类的成员函数也注册给了lua

 

     以下为C函数与类成员函数封装代码(为了简便,函数都是 int fun() 形式):

    

     /*

     调用真正的C函数,现已int func()作为特例。

    

     参数 func 函数指针,指向参数为返回值为int类型的函数

              L lua变量

              index lua栈中索引

    

     对于其他的类型,可用模板实现

     如对于一个参数的函数,实现如下

     template <typname RT, typename P1>

     int callFunc(RT (*func)(P1), lua_state *L, int index)

     {

         //Get 通过index索引得到在lua栈中的值并转换成P1类型

         //Push 把函数的返回值压入堆栈

         RT ret = func(Get(Type<P1>(), L, index + 0));

         Push(L, ret);

         return 1;

     }

     */

 

     int callFunc(int (*func)(), lua_State *L, int index)

     {

          int ret = func();

          lua_pushnumber(L, ret);

          return 1;

     }

 

     //函数指针相关数据会存到UpValue的第一个值中,此处从upvalue中取出

     unsigned char* getFirstUpValue(lua_State *L)

     {

          unsigned char* buffer = (unsigned char*)lua_touserdata(L, lua_upvalueindex(1));

          return buffer;

     }

 

     /*

          实现callFunclua调用形式封装

     */

     template <typename Func>

     int directCallFunc(lua_State *L)

     {

          //得到函数指针

          unsigned char* buffer = getFirstUpValue(L);

          //转换成相应的函数调用

          return callFunc(*(Func*)(buffer), L, 1);

     }

 

     /*

          directCallFunc注册进lua

     */

     template <typename Func>

     void lua_pushdirectclosure(lua_State *L, Func func, unsigned int nupvalues)

     {

          //创建userdata并把func指针的值拷贝进去

          unsigned char* buffer = (unsigned char*)lua_newuserdata(L, sizeof(func));

          memcpy(buffer, &func, sizeof(func));

 

          lua_pushcclosure(L, directCallFunc<Func>, nupvalues + 1);

     }

 

 

 

     /*

          实现对class里面memeber function的调用

          参数cla 要调用的类的实例

               Cla::*func 类的函数指针

     */

     template <typename Cla>

     int callMemFunc(Cla &cla, int (Cla::*func)(), lua_State *L, int index)

     {

          int ret = (cla.*func)();

          lua_pushnumber(L, ret);

          return 1;

     }

 

     /*

          实现callMemFunclua调用形式封装

     */

     template <typename Cla, typename Func>

     int directCallMemFunc(lua_State *L)

     {

          //得到函数指针

          unsigned char* buffer = getFirstUpValue(L);

          //转换成相应的函数调用

          return callMemFunc(*(Cla*)(buffer), *(Func*)(buffer + sizeof(Cla)), L, 1);

     }

 

     /*

          directCallMemFunc注册进lua

     */

     template <typename Cla, typename Func>

     void lua_pushdirectmemclosure(lua_State *L, Cla &cla, Func func, unsigned int nupvalues)

     {

          //创建userdata并把clafunc指针的值拷贝进去

          unsigned char* buffer = (unsigned char*)lua_newuserdata(L, sizeof(Cla) +            sizeof(func));

          memcpy(buffer, &cla, sizeof(Cla));

          memcpy(buffer + sizeof(Cla), &func, sizeof(func));

          lua_pushcclosure(L, directCallMemFunc<Cla, Func>, nupvalues + 1);

     }

 

     #define lua_directregistry_function(L, func) /

          lua_pushstring(L, #func); /

          lua_pushdirectclosure(L, func, 0); /

          lua_settable(L, LUA_GLOBALSINDEX);

 

     #define lua_directregistry_memfunction(L, name, cla, func) /

          lua_pushstring(L, name); /

          lua_pushdirectmemclosure(L, cla, func, 0); /

          lua_settable(L, LUA_GLOBALSINDEX);

 

     使用的时候我们通过lua_directregistry_function()注册c函数,
    
通过lua_directregistry_memfunction()注册类成员函数,其中name为该成员函数在lua中使用的函数名。

    

    

 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值