Lua5.3 与C交互学习(一)

C++中引入lua环境搭建

  • 第一种: 联合的方式(不方便)
    1. 下载lua5.3.1 tar.gz
    2. 创建控制台项目, 静态库, 取消预编译头;
    3. C/C++>常规>附加包含目录: 加入5.3.1\src
    4. 编译得到lublib.lib
    5. 创建新工程
    6. 在vc++目录里添加包含目录 和库目录;
    7. 连接器里添加lualib.lib
    8. 编译; 如果失败则拷贝lualib.lib到根目录dubug下;
    9. OK
  • 第二中: 生成静态库
    1. 新建控制台项目, 静态库, 取消预编译头;
    2. 将5.3.2的src中添加到项目中, 但 不要添加lua.c
    3. 编译得到xxx.lib, 这就是所得到的静态库
    4. 建立一个文件夹如lua5.3,分别在子文件夹lib里放入刚生成的xxx.lib(可以改名为lua5.3.2.lib)和include子文件夹里放入lua头文件: lauxlib.h, lua.h, luaconf.h, lualib.h
    5. 新建C++项目, 在”项目属性>VC++目录>包含目录和库目录里”添加上面的lib和include路径;
    6. “项目属性>连接器>输入”里添加lua5.3.2.lib
    7. OK
#include <stdio.h>
#include <string.h>

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
int main(int argc, char* argv[])
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);  // 加载Lua通用扩展库

    if(luaL_loadfile(L,"test.lua"||lua_pcall(L,0,0,0))  //或luaL_dofile(L,"test.lua")
        printf("error pcall!: %s\n",lua_tostring(L,-1));
    // 前面搭建了运行环境,lua代码写在了test.lua文件中
    // ......
    //
    lua_close(L);
    return 0;
}       

C++调用Lua函数

要在C++中调用lua函数,则有如下函数可以利用:
lua_getglobal()就是从lua中取得函数,压入栈中;随后压入函数的参数;

如在test.lua中有如下代码:

function he(x,y)
    return x*y
end

则的C++中的调用过程是:

//.....
lua_getgloabl(L,"he");
lua_pushnumber(L,5);
lua_pushnumber(L,6);
// run the lua program
// lua_pcall(L,nargs,nresults,0)
if(lua_pcall(L,2,1,0) != 0)
    printf("error pcall!: %s\n",lua_tostring(L,-1)); 
// if error then push errorinfo in the stack else push reuslts
if(!lua_isnumber(L,-1))
    printf("error return!\n");
int re = (int)lua_tonumber(L,-1);

函数参数、返回值压栈是正序压栈;如果有错误发生的话, lua_pcall 会捕获它,然后把单一的值(错误信息)压入堆栈,然后返回错误码。lua_pcall 总是把函数本身和它的参数从栈上移除。


Lua中调用C++函数

  • 要写一个能让Lua调用的C函数,就要符合lua_CFunction定义:typedef int (*lua_CFunction) (lua_State *L); //return 返回值的个数
  • 当Lua调用C函数的时候,同样使用栈来交互。C函数从栈中获取她的参数,调用结束后将结果放到栈中,并返回放到栈中的结果个数。
  • 这儿有一个重要的概念:用来交互的栈不是全局栈,每一个C函数都有他自己的私有栈。当Lua调用C函数的时候,第一个参数总是在这个私有栈的index=1的位置。
 如:函数he
// 普通函数
 static int he(lua_State* L)
 {
 // 从栈中检查参数是否合法并读取参数,
 int a = luaL_checknumber(L,1);
 int b = luaL_checknumber(L,2);
 int re = a*b;
 // 将运算结果返回栈中供lua使用
 lua_pushnumber(L,re);
 return 1;
 }


 // 在C++中向lua传递table结构的数据
 // 这里的table是:{{"he"},{"li"}}
 int TTable(lua_State* L)
 {
   // 创建大table
   lua_newtable(L,1);

   // 大table的key
   lua_pushnumber(L,1); // 1为键
   //第一个小table
   lua_newtable(L);  
   // 第一个小table的key,value
   lua_pushnumber(L,1);
   lua_pushstring(L,"he");
   lua_settable(L,-3);
   //第一个小table的成员结束
   lua_settable(L,-3);
   //第二个小table,类似上面的过程
   lua_pushnumber(L,2); // 2为键
   lua_newtable(L,2);
   lua_pushnumber(L,1);
   lua_pushstring(L,"li");
   lua_settable(L,-3);
   lua_settable(L,-3)
   return 1;  //1个大table
 }

在main中可以使用lua_dostring()lua_loadfile()lua_pcall(L,0,0,0) 来执行lua代码:

int main(int argc, char* argv[])
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);  // 加载Lua通用扩展库
    // 将he函数注册成lua的全局函数
    lua_register(L,"he",he);
    if(luaL_loadfile(L,"test.lua")/*||lua_pcall(L,0,0,0)*/)
        printf("error pcall!: %s\n",lua_tostring(L,-1));
    lua_close(L);
    return 0;
}

.lua文件文间之间的全局变量调用

比如有两个文件

//a.lua
a = 50
local b = 10

//h.lua
dofile("X:/.../a.lua")  
//或在同一个目录下时:doflie("a.lua"),require会更好
print(a,b)

lua中:
h.lua想要调用a.lua中的内容则要在a.lua中运行dofile("X:/.../a.lua")

C++中两种方法:

  • 如上面所示, 在h.lua中使用dofile(“a.lua”), 文件放同一个目录;
  • 或在C代码加载时先用luaL_dofile(L,"a.lua");luaL_dofile(L,"h.lua"); 顺序不能变;

引入C模块到 lua

  • luaL_register
    这个函数接收一些C函数及其名称,并将这些函数注册到一个与模块同名的table中。假设创建一个模块,其中包含了这个luaglue函数。首先,必须定义这个模块函数:
static int luaglue(lua_state *L)
{
}

然后,声明一个数组,其中包含模块中所有函数及名称。这个数组元素的类型为luaL_Reg结构,该结构有两个字段,一个字符串和一个函数指针:

static const struct luaL_Reg mylib[] = {
{"dir",l_dir},
{NULL,NULL}//结尾
};

最后,声明一个主函数,其中用到了luaL_register:

int luaopen_mylib(lua_State *L)
{
     luaL_register(L,"mylib",mylib);
     return 1;
}

其中luaL_register原型为:

void luaL_register (lua_State *L,const char *libname,const luaL_Reg *l);

luaL_register根据给定的名称(“mylib”)创建(或复用)一个table,并用数组mylib中的信息填充这个table。在luaL_Register返回时,会将这个table留在栈中。最后,luaopen_mylib函数返回1,表示将这个table返回给Lua。

打开一个库,当libname为null时,该函数注册所有在luaL_Reg上的函数,不为null时,该函数会创建一个table,根据libname注册不与libname关联的函数。

  • 当写完c模块后,必须将其链接到解释器。如果Lua解释器支持动态链接的话,那么最简便的方法是使用动态链接机制。在这种情况中,必须将c代码编译成动态链接库,并将这个库放入C路径(LUA_CPATH)中。然后,便可以用require从Lua中加载这个模块:
require "mylib"

这个调用会将动态库mylib链接到Lua,并会寻找luaopen_mylib函数,将其注册为一个Lua函数,然后调用它以打开模块。
如果解释器不支持动态链接,那么就必须用新的模块来重新编译Lua。此外,还需要以某种方式来告诉解释器,它应在打开一个新状态的同时打开这个模块。最简单的做法是,将luaopen_mylib加到luaL_openlibs会打开的标准库列表中,这个列表在文件linit.c中。
从C++程序员的观点来看,Lua像一个“黑盒子”,为一些服务处理命令和调用。Lua通常作为最上层接口直接和程序使用者和游戏玩家打交道,在核心程序处理之前接受并响应输入。


lua5.3 C++注册函数或模块到lua

//要注册的lua里的C++函数的写法这里就不说了,随便写一个
static int f(lua_State* L)
{
    printf("hello\n");
    return 0;
}
// .... 还可以继续添加
//注册函数数组
const luaL_Reg mylib[] = 
{
    {"myf",f},
    //{//可以继续添加},
    {NULL,NULL}
}
//定义一个库打开函数
static luaopen_mylib(lua_State* L)
{
    //lua5.1 是luaL_register(L,"mylib",mylib)来完成
    // lua5.2以上是
    lua_newlib(L,mylib);
    //或者等效为下面
    luaL_newlibtable(L,mylib);
    lubL_setfuncs(L,func,0);
    return 1;
}
//如果有多个库可以在用个库数组来进行注册如下
// 可不用
const luaL_Reg lualibs[]=
{
    {"mylib",luaopen_func}, //打开库函数
    {/*其它库*/},
    {NULL,NULL},
}

到这里,我们可以选择去将库导出为.dll来在lua中调用,这个网上好多资料,在lua中要用local mylib = require "mylib"来获取.dll文件, 参考
http://blog.csdn.net/ljhjason/article/details/28860633
这里选择不导出为.dll所以进行如下操作:

 int main
 {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    // 打开自己的库如果用了lublibs库数组则用循环打开
    luaL_requiref(L,"mylib",luaopen_mylib,1);
    lua_pop(L,1);
    luaL_dofile("xxx.lua");
    ....
}

注册C++类到lua

http://blog.csdn.net/siddontang/article/details/2316547


C++ struct对应到lua table


// 压入表的键值对函数(没有进行栈检测)
inline void PushTableKV(lua_State* L, const char* k, int v)
{
lua_pushstring(L,k);
lua_pushnumber(L,v);
lua_settable(L,-3);
}
// 使用时候
{
lua_newtable(L)
PushTableKV(L,"v1",10);
....
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呵离

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值