zoukankan      html  css  js  c++  java
  • lua与c之间交互详解(三)

    本篇主要讲解Lua是如何调用c的,Lua是宿主语言,c是附加语言,关于c如何调用Lua参考其他两篇。Lua调用c有几种不同方式,这里只讲解最常用的一种:将c模块编译成so库,然后供Lua调用。

    gcc mylib.c -fPIC -shared -o mylib.so -I/usr/local/include/

    约定:c模块需提供luaopen_xxx接口,xxx与文件名必须一致,比如"mylib";还需提供一个注册数组(55-60行),该数组必须命名为luaL_Reg,每一项是{lua函数名,c函数名},最后一项是{NULL, NULL};通过luaL_newlib创建新的表入栈,然后将数组中的函数注册进去,这样Lua就可以调用到。

     1 //mylib.c
     2 
     3 #include <lua.h>
     4 #include <lauxlib.h>
     5 #include <lualib.h>
     6 
     7 #define TYPE_BOOLEAN 1
     8 #define TYPE_NUMBER 2
     9 #define TYPE_STRING 3
    10 
    11 static int ladd(lua_State *L){
    12     double op1 = luaL_checknumber(L, -2);
    13     double op2 = luaL_checknumber(L, -1);
    14     lua_pushnumber(L, op1+op2);
    15     return 1;
    16 }
    17 
    18 static int lsub(lua_State *L){
    19     double op1 = luaL_checknumber(L, -2);
    20     double op2 = luaL_checknumber(L, -1);
    21     lua_pushnumber(L, op1-op2);
    22     return 1;
    23 }
    24 
    25 static int lavg(lua_State *L){
    26     double avg = 0.0;
    27     int n = lua_gettop(L);
    28     if(n==0){
    29         lua_pushnumber(L,0);
    30         return 1;
    31     }
    32     int i;
    33     for(i=1;i<=n;i++){
    34         avg += luaL_checknumber(L, i);
    35     }
    36     avg = avg/n;
    37     lua_pushnumber(L,avg);
    38     return 1;
    39 }
    40 
    41 static int fn(lua_State *L){
    42     int type = lua_type(L, -1);
    43     printf("type = %d
    ", type);
    44     if(type==LUA_TBOOLEAN){
    45         lua_pushvalue(L, lua_upvalueindex(TYPE_BOOLEAN));
    46     } else if(type==LUA_TNUMBER){
    47         lua_pushvalue(L, lua_upvalueindex(TYPE_NUMBER));
    48     } else if(type==LUA_TSTRING){
    49         lua_pushvalue(L, lua_upvalueindex(TYPE_STRING));
    50     }
    51     return 1;
    52 }
    53 
    54 int luaopen_mylib(lua_State *L){
    55     luaL_Reg l[] = {
    56         {"add", ladd},
    57         {"sub", lsub},
    58         {"avg", lavg},
    59         {NULL, NULL},
    60     };
    61     luaL_newlib(L,l);
    62 
    63     lua_pushliteral(L, "BOOLEAN");
    64     lua_pushliteral(L, "NUMBER");
    65     lua_pushliteral(L, "STRING");
    66     lua_pushcclosure(L, fn, 3);
    67 
    68     lua_setfield(L, -2, "fn");
    69     return 1;
    70 }

    Lua文件里,需将so库加入cpath路径里,通过require返回栈上的表,Lua就可以调用表中注册的接口,比如,add、sub、avg等

    Lua调用c api的过程:Lua将api需要的参数入栈——c提取到参数——处理——c将结果入栈——Lua提取出结果

     1 package.cpath = "./?.so"
     2 
     3 local mylib = require "mylib"
     4 
     5 local a, b = 3.14, 1.57
     6 
     7 print(mylib.add(a, b), mylib.sub(a, b))   -- 4.71. 1.57
     8 
     9 print(mylib.avg())  -- 0.0
    10 
    11 print(mylib.avg(1,2,3,4,5)) -- 3.0
    12 
    13 print(mylib.fn(true), mylib.fn(10), mylib.fn("abc")) -- BOOLEAN NUMBER STRING

     示例中还提供了简单的c闭包的使用方法(63-68行),关于c闭包,提供了多个上值(upvalue)关联到函数上,这些upvalue可以理解成该函数内部的全局变量,即只能被该函数访问到,且在函数返回时不会消亡,该函数任何时候都可以访问到。

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

    用来把一个新的c闭包压栈,fn是一个c api,n指定关联多少个upvalue,这些upvalue需要依次压栈,即栈顶位置是第n个upvalue的值,lua_pushcclosure会把这些upvalue出栈,这些upvalue的伪索引依次为1-n。

    int lua_upvalueindex (int i);

    获取当前运行函数第i个upvalue的值。

    总之,Lua调用c的流程:编写好c模块,在堆栈上建一个表,将接口注册给这个表,然后把c模块编译成so库,在Lua里require这个so库,就可以调用注册的函数了。

  • 相关阅读:
    Java的char是16位的unicode类型
    Leetcode_907. 子数组的最小值之和(单调栈)
    Leetcode_34. 在排序数组中查找元素的第一个和最后一个位置
    Leetcode_739. 每日温度(单调栈)
    Leetcode_1048. 最长字符串链
    Leetcode_877. 石子游戏(区间dp)
    Leetcode_面试题 17.24. 最大子矩阵
    Leetcode_面试题 17.08. 马戏团人塔(二维LIS)
    C#委托和事件的简单实例
    WPS快速下拉填充公式
  • 原文地址:https://www.cnblogs.com/RainRill/p/8400198.html
Copyright © 2011-2022 走看看