您的位置:首页 > 编程语言 > Lua

Lua5.3 与C交互学习

2015-10-07 16:57 549 查看

C++调用Lua函数

main函数中环境搭建

下载lua5.3.1 tar.gz

创建控制台项目, 静态库, 取消预编译头;

C/C++>常规>附加包含目录: 加入5.3.1\src

编译得到lublib.lib

创建新工程

在vc++目录里添加包含目录 和库目录;

连接器里添加lualib.lib

编译; 如果失败则拷贝lualib.lib到根目录dubug下;

OK



[code]#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函数,则有如下函数可以利用:

lua_getglobal()
就是从lua中取得函数,压入栈中;随后压入函数的参数;

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

[code]function he(x,y)
    return x*y
end


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

[code]//.....
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

[code] 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;
 }


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

[code]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文间之间的全局变量调用

比如有两个文件


[code]//a.lua
a = 50
local b = 10


[code]//h.lua
dofile("X:/.../a.lua")  //或在同一个目录下时:doflie("a.lua")
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函数。首先,必须定义这个模块函数:


[code]static int luaglue(lua_state *L)
{
}


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


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


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


[code]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。

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

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


[code]require "mylib"


这名调用会将动态库mylib链接到Lua,并会寻找luaopen_mylib函数,将其注册为一个Lua函数,然后调用它以打开模块。

如果解释器不支持动态链接,那么就必须用新的模块来重新编译Lua。此外,还需要以某种方式来告诉解释器,它应在打开一个新状态的同时打开这个模块。最简单的做法是,将luaopen_mylib加到luaL_openlibs会打开的标准库列表中,这个列表在文件linit.c中。

从C++程序员的观点来看,Lua像一个“黑盒子”,为一些服务处理命令和调用。Lua通常作为最上层接口直接和程序使用者和游戏玩家打交道,在核心程序处理之前接受并响应输入。

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

上面的那个luaL_register函数在lua5.2以后就没有用了,所以一直在找5.2以后版本的用法, 网上找了半天都没有指出重点,最后在下面的网站上找到;

http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/

结合下面两篇介绍后这里给出一些理解:

http://www.linuxidc.com/Linux/2014-05/102528p2.htm

http://blog.163.com/cqit_jsj/blog/static/65127220127251231881/


[code]//要注册的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

/article/1594738.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: