lua5.3调用C/C++

马上面临毕业设计,打算做点跟网游有关的,先从做周边工具开始,目前正在做一个协议序列化和反序列化的东西,广告一波先: https://github.com/Anti-Magic/rproto

目前非常简陋,功能还没做完,不要当真。。

因为目标是绑定到lua,作为一个独立的库,不想对项目有依赖,这样的好处是客户端和服务端都可以方便的拿来用,所以打算手动绑定。

我夜观天象发现,到目前为止网上找不到针对lua5.3的这么简明扼要且完整的示例,转载注明出处:http://www.cnblogs.com/wolfred7464/p/5147675.html

由于lua提供的require函数可以引入C语言的动态链接库,对于使用者来说,不需配置,只要调用require就可以,肯定是最简单的方法。(其实iOS不能这样做的,唉,习惯就好)

首先读者需要对lua提供的操作虚拟栈的函数比较熟悉,不熟悉的先翻手册吧:http://cloudwu.github.io/lua53doc/manual.html

先上一段简单的示例,功能是使用C语言编写一个计算2个浮点数之和的add函数,绑定到lua由lua调用:

 1 #include "lua.h"
 2 #include "lualib.h"
 3 #include "lauxlib.h"
 4 #include "luaconf.h"
 5
 6 double add(double x, double y) {
 7     return x+y;
 8 }
 9
10 static int ladd(lua_State* L) {
11     double x = luaL_checknumber(L, 1);
12     double y = luaL_checknumber(L, 2);
13     lua_pushnumber(L, add(x+y));
14     return 1;
15 }
16
17 int luaopen_xxx(lua_State* L) {
18     luaL_checkversion(L);
19
20     struct luaL_Reg funcs[] = {
21         {"add", ladd},
22         {NULL,  NULL}
23     };
24     luaL_newlib(L, funcs);
25     return 1;
26 }

在linux使用gcc编译:

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

lua的package.cpath中需要能搜索到我们的so,设置cpath的方法网上搜一下有很多。然后lua代码中这样调用:

1 local xxx = require "xxx"
2 print(xxx.add(45, 5))

最后在终端执行:

lua test.lua

这个例子就跑起来了,虽然步骤说不上多简单,但是足够清晰吧。。为了简单,我就不写检查参数数量和类型是否匹配的代码了,后面的例子也是。

如何使用lua调用C++呢?只要你会操作userdata,基本上照搬上面的C语言的方式就可以,只不过显式传递C++的this指针就可以。再上一个简单的代码:

 1 #include <lua.hpp>
 2
 3 class TTT {
 4 public:
 5     TTT() {}
 6     ~TTT() {}
 7
 8     double add(double x, double y) {
 9         return x+y;
10     }
11 };
12
13 extern "C"
14 {
15     static int lnewTTT(lua_State* L) {
16         TTT** p = (TTT**)lua_newuserdata(L, sizeof(TTT*));
17         *p = new TTT();
18         return 1;
19     }
20
21     static int ldelTTT(lua_State* L) {
22         TTT** p = (TTT**)lua_topointer(L, 1);
23         delete *p;
24         *p = nullptr;
25         return 0;
26     }
27
28     static int ladd(lua_State* L) {
29         TTT** p = (TTT**)lua_topointer(L, 1);
30         TTT* pt = *p;
31         lua_pushnumber(L, pt->add(lua_tonumber(L, 2), lua_tonumber(L, 3)));
32         return 1;
33     }
34
35     int luaopen_xxx(lua_State* L) {
36         luaL_checkversion(L);
37         luaL_openlibs(L);
38
39         struct luaL_Reg funcs[] = {
40             {"new", lnewTTT},
41             {"add", ladd},
42             {"del", ldelTTT},
43             {NULL,  NULL}
44         };
45         luaL_newlib(L, funcs);
46         return 1;
47     }
48 }

1 local xxx = require "xxx"
2 local t = xxx.new()
3 print(xxx.add(t, 3, 4))
4 xxx.del(t)

(为什么要使用指针的指针呢?因为lua申请内存和释放内存时不会调用C++的构造函数和析构函数,我们又不能手动去调用,只能使用指针的指针,便于手动调用构造和析构函数了。)

使用lua的userdata保存this指针,然后作为参数传递到绑定函数,然后C语言就可以调用了,第一个例子明白后,这个没什么难度。

但是这样做有三个问题:一是无法检查lua传来的this指针是否是正确的类型,二是需要手动释放内存,三是lua代码中调用起来太麻烦。

这三个问题有一个共同的解决方案:元表(metatable)。

1、给同一类userdata设置同一个元表,利用元表就可以区别不同类型的userdata。

2、lua垃圾回收时会调用元表中的"__gc"元方法,我们可以利用这个元方法析构C++对象。

3、索引字段会调用"__index"方法,不存在这个方法时会从元表中查找,利用这个特性我们可以把red.add(t, x, y)这样的调用变成t.add(t, x, y),然后就可以写成t:add(x, y)了。

把第二个例子中的lnewTTT和luaopen_xxx两个函数修改一下就可以,上代码:

 1 static int lnewTTT(lua_State* L) {
 2     TTT** p = (TTT**)lua_newuserdata(L, sizeof(TTT*));
 3     *p = new TTT();
 4     luaL_getmetatable(L, "xxx.TTT");
 5     lua_setmetatable(L, -2);
 6     return 1;
 7 }
 8
 9 int luaopen_xxx(lua_State* L) {
10     luaL_checkversion(L);
11     luaL_openlibs(L);
12
13     struct luaL_Reg funcs[] = {
14         {"new", lnewTTT},
15         {NULL,  NULL}
16     };
17
18     struct luaL_Reg funcs_meta[] = {
19         {"add", ladd},
20         {NULL,  NULL}
21     };
22
23     luaL_newmetatable(L, "xxx.TTT");
24     lua_pushstring(L, "__gc");
25     lua_pushcfunction(L, ldelTTT);
26     lua_settable(L, -3);
27     lua_pushstring(L, "__index");
28     lua_pushvalue(L, -2);
29     lua_settable(L, -3);
30     luaL_setfuncs(L, funcs_meta, 0);
31     luaL_newlib(L, funcs);
32     return 1;
33 }

1 local xxx = require "xxx"
2 local t = xxx.new()
3 print(t:add(3, 4))

基本上就是这样了,绑定其他的数据类型,或者保存上下文等,都可以查找手册解决,lua天生为了嵌入宿主语言而设计,与C语言的交互有天然的优势。

时间: 2024-07-28 16:55:08

lua5.3调用C/C++的相关文章

thrift for lua 使用记录

本人精心总结,欢迎转载,转载请注明出处:http://blog.csdn.net/einsteinlike/article/details/43700985 thrift是一个十分节省的数据传输协议,我们尝试将其移植到quick-cocos2dx上面: lua的使用:首先编译lua5.2 make install进系统.然后编译thrift 0.9.2 ,配置的时候选择 ./configure -with-lua -with-c++等 然后make的时候各种有错,没关系,只要到make lua结

Lua中调用C函数(lua-5.2.3)

Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性. 对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数. 对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L). 简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数.返回值是整型,表示该

简述C/C++调用lua中实现的自定义函数

1.首先说下目的,为什么要这么做 ? 正式项目中,希望主程序尽量不做修改,于是使用C/C++完成功能的主干(即不需要经常变动的部分)用lua这类轻量级的解释性语言实现一些存在不确定性的功能逻辑:所以,程序功能如有问题,只需对lua脚本作出修改,而修改脚本的好处是简单高效,改完脚本后重新执行程序便能看到效果.  2.具体怎么做? 一般来说,C/C++调用lua接口或是数据交互,首先要做的是包含lua相关操作的头文件以及lua库相关的头文件,然后调用接口创建lua环境.用操作栈的规则和lua交互数据

C程序与Lua脚本相互调用

Lua脚本是一种可用于C程序开发/测试的工具,本篇介绍一下C程序与Lua脚本如何进行相互调用,更加详细的操作参见<Programing in Lua>.本文分为3个部分:1.Windows环境下Lua的下载以及安装注意事项:2.Visual C++6.0中Lua的配置:3.C程序与Lua脚本相互调用实例. 1.Windows环境下Lua的下载以及安装注意事项 a.下载Lua for Windows,笔者用的版本是V5.1.4-35: b.上微软官网,下载Visual C++运行库——vcred

vs项目中使用c++调用lua

在前一篇文章中,我们已经讲了如何编译lua源码并生成lua.lib(请阅读 使用vs2010编译lua5.1源码生成lua.lib),在新的项目中,我们继续使用之前的项目来学习如何使用c++调用lua. 一.创建项目 同样在该解决方案中,右键解决方案->添加项目->命名为testlua,选择win32控制台程序->不需要其他配置,选择完成. 二.配置项目 右键testlua项目->通用属性->框架和引用->添加新引用,指向lua项目. 右键testlua项目->配

LUA脚本调用C场景,使用C API访问脚本构造的表

LUA调用C lua解析中集成了一些系统服务, 故脚本中可以访问系统资源, 例如, lua脚本可以调用文件系统接口, 可以调用数学库, 但是总存在一些lua脚本中访问不到的系统服务或者扩展功能, 如果这些系统服务或者扩展功能是使用C语言实现, 那么可以, 使用lua库的对C库的封装方法, 将其中功能封装成lua 接口, 这样脚本就调用这些lua接口调用这些功能. ------- 这种情况,是以lua脚本作为宿主程序. C调用LUA 另外一种场景,是C程序作为宿主程序, 调用LUA脚本, 例如将l

lua编程之lua与C相互调用

lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情况下修改lua代码更新程序,也可以给用户提供一个自由定制的接口,这种方法遵循了机制与策略分离的原则.在lua中调用C函数可以提高程序的运行效率.lua与C的相互调用在工程中相当实用,本文就来讲解lua与C相互调用的方法. Lua与C相互调用的首要问题是如何交换数据,lua API使用了一个抽象的栈与

Win7 64位 VS2013环境编译Lua5.3.1

主要参考这篇文章,原文有几个错误顺便改正了. 在Windows下使用Visual Studio编译Lua5.3 写本文时Lua官方网站放出的新版本为5.3.1,然后我不知道为啥,神奇的国内不能访问Lua官网,但是作为程序员搞到源码应该不是难事. VS2013中新建工程,设置如图 工程名Lua53,并且勾选Create directory for solution 应用程序设置静态库,其他选项全去掉 首先删除Lua源码文件夹中的Makefile文件,我们用不着这东西,至少我不用... 然后把除 l

lua与c++的相互调用

一.   lua调用C++       在lua中是以函数指针的形式调用函数, 并且所有的函数指针都必须满足如下此种类型: typedef int (*lua_CFunction) (lua_State *L); 也就是说, 偶们在C++中定义函数时必须以lua_State为参数, 以int为返回值才能被Lua所调用. 但是不要忘记了, 偶们的lua_State是支持栈的, 所以通过栈可以传递无穷个参数, 大小只受内存大小限制. 而返回的int值也只是指返回值的个数真正的返回值都存储在lua_S