如何在cpp中实现自定义lua库

如果需要在lua中需要能够调用cpp的代码,

local testlib = require("testlib")
testlib.luacallcfunc()

那么在cpp中这样写

extern "C" {
#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "lua/lualib.h"
}
#include <iostream>

static int lluacallcfunc(lua_State *L) {
    std::cout << "hello in cpp" << std::endl;
    return 0;
}
static const struct luaL_Reg testlib[] = {
        {"luacallcfunc",lluacallcfunc},
        {NULL, NULL}
};
static int luaopen_testlib(lua_State *L) {
    luaL_newlib(L,testlib);
    return 1;
}
int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_requiref(L, "testlib", luaopen_testlib, 0);
    char *luafile = argv[1];
    luaL_dofile(L, luafile);
    lua_close(L);
    return 0;
}

如果lua需要带参数

testlib.luacallcfunc(12,"abc")

那么在cpp中

static int lluacallcfunc(lua_State *L) {
    int intv = lua_tonumber(L, 1);//传入的第一个参数为int
    const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string
    return 0;
}

如果lua函数有返回结果

local a = testlib.luacallcfunc(12,"abc") --a=10

那么在cpp中

static int lluacallcfunc(lua_State *L) {
    int intv = lua_tonumber(L, 1);//传入的第一个参数为int
    const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string
    lua_pushnumber(L,10);
    return 1;//这里是lua函数返回值的个数
}

如果lua的参数是一个table,那么使用lua_gettable等函数来获取。
这里需要介绍一下栈
其中栈底上标是1,2,3,4
栈顶下标可以用 -1,-2,-3,-4来表示
如图


Selection_141.png

当调用了
testlib.luacallcfunc(12,"abc")时,栈上的内容为


Selection_142.png

当在cpp里调用 lua_pushnumber(L,10);时
Selection_143.png

如果 参数是table呢
假设在lua中调用了
testlib.luacallcfunc(12,"abc",{a="cba"})


Selection_144.png

这时在cpp 中
lua_pushstring(L,"a"); 将key推到栈顶


Selection_147.png

再调用 lua_gettable(L, tIdx);会变成
Selection_145.png

这时就可以把那个值取出来了。
当用完之后,需要回退之前的栈的内容。

则调用lua_pop(L, 1);这时


Selection_146.png

总结:
lua与c传递数据是通过一个叫栈的数据结构来进行的。
其中栈底上标是1,2,3,4
栈顶下标可以用 -1,-2,-3,-4来表示(其实也可以 用 栈长-1,栈长-2..来表示)

栈底的数据可以认为是lua传给c的(简单数据类型的数据可通过lua_toxxx(L,idx)来获取)。
相对,在函数的return value中,表示栈顶value个数据是c传给lua的(即在lua函数调用库函数时的返回值)。
往栈顶上塞数据可以用lua_pushxxx 来实现。
当然栈顶的数据也还可以被其它函数修改。(具体就要看lua的api了)
所以如果有调用那些函数,栈顶在运行的过程中数据是时不时在变化的。
当你获取完栈顶的数据,然后又不需要它时,调用一下lua_pop(L,1),即可把栈顶数据pop掉。
如果有使用修改栈顶数据的函数,需要知道每一行代码运行后,栈顶的数据是什么。

下面是完整的代码

extern "C" {
#include "lua/lauxlib.h"
#include "lua/lua.h"
#include "lua/lualib.h"
}

static int getTableIntValue(lua_State *L, int tIdx, const char *key) {
    lua_pushstring(L, key);//将key推到栈顶
    lua_gettable(L, tIdx);//将t[key]推到栈顶,并把key移走( 不知道先走哪一步 )
    int ret = lua_tonumber(L, -1); //把值给弄出来
    lua_pop(L, 1);//把栈顶元素移走,恢复栈
    return ret;
}

static int lluacallcfunc(lua_State *L) {
    int intv = lua_tonumber(L, 1);//传入的第一个参数为int
    const char *szStr = lua_tostring(L, 2); //传入的第二个参数为string

    int tableIdx = 3; //传入的第三个参为是一个table
    if (lua_istable(L, tableIdx) == 0) {
        lua_pushnil(L);
        return 1;
    }

    int tableStrKeyValue = getTableIntValue(L, tableIdx, "tableStrKey");

    const char *arrElemntKey = "arrKey";
    lua_pushstring(L, arrElemntKey); //将key推到栈顶
    lua_gettable(L, tableIdx); //将t[key]推到栈顶,并把key移走( 不知道先走哪一步 )
    size_t len = lua_rawlen(L, -1); //栈顶是一个数组类型的table 可以使用 lua_rawxxx功能
    for (size_t i = 1; i <= len; i++) {
        lua_rawgeti(L, -1, i); //把 arr[i]推到栈顶  现在栈顶是arr[i]
        const char *png = lua_tostring(L, -1);//数组里的元素是一个 string
        lua_pop(L, 1); //恢复栈顶,现在栈顶是是 arr
    }
    lua_pop(L, 1); //恢复栈顶,把arr移走。

    int ret = 0;
    lua_pushnumber(L, ret);
    return 1;
}


static const struct luaL_Reg testlib[] = {
                                            {"luacallcfunc",lluacallcfunc},
                                            {NULL, NULL}
                                            };

static int luaopen_testlib(lua_State *L) {
    luaL_newlib(L,testlib);
    return 1;
}

int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_requiref(L, "testlib", luaopen_testlib, 0);
    char *luafile = argv[1];
    luaL_dofile(L, luafile);
    lua_close(L);
    return 0;
}
--lua
local function main()
    local testlib = require("testlib")
    print(testlib.luacallcfunc(1,"abc",{tableStrKey=1,arrKey={"a","b"}}))
end
xpcall(main,print)--当lua有报错的时候,可以打印出来。

会打印出: 0


附:api 注释

void luaL_requiref (lua_State *L, const char *modname,lua_CFunction openf, int glb);
//在lua中 require时,会调用到 openf的函数 glb!=0 时,也注册为全局
typedef int (*lua_CFunction) (lua_State *L); 
//能让lua/c 中正确交互的函数
//一个简单的例子:
static int foo (lua_State *L) {
       int n = lua_gettop(L);    /*变量个数 */
       lua_Number sum = 0.0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushliteral(L, "incorrect argument");//提示错语信息
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /*第一个result*/
       lua_pushnumber(L, sum);         /* 第二个result*/
       return 2;                   /* result 的个数 */
     }
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
//新建一个table 并向那个table 注册 所有在 l  luaL_Reg 函数
//这个函数实现如下:
     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

luaL_Reg 的定义如下

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
//创建 一个table,刚好能把l 里的放进去  注意:这个table 的大小是合适的,但是并没有把l 里的函数给赋过去
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);\
//把l里的所有函数注册到 top里的table中去
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,766评论 0 38
  • lua作为小巧精悍的脚本语言,易于嵌入c/c++中 , 广泛应用于游戏AI ,实际上在任何经常变化的逻辑上都可以使...
    木易林1阅读 1,500评论 0 4
  • 第一篇 语言 第0章 序言 Lua仅让你用少量的代码解决关键问题。 Lua所提供的机制是C不擅长的:高级语言,动态...
    testfor阅读 2,659评论 1 7
  • 最近项目中提到需要调用Lua,所以简单的研究了一下,也看了不少网上大佬的文章,在这就简单的写一下收获吧。下载和编译...
    iOS_zy阅读 6,590评论 2 12
  • 按键说明 F1帮助 Alt+F1查找文件所在目录位置 Alt+1快速打开或隐藏工程面板 Ctrl+Alt+S打开设...
    发财哥阅读 1,153评论 0 3