Lua和C++的通信流程代码实例_Lua

上一章传送门:http://www.jb51.net/article/55088.htm

本章我们来学习一个小Demo,也就是上一章中的场景:C++从Lua中获取一个全局变量的字符串。

1. 引入头文件

我们来看看要在C++中使用Lua,需要些什么东西

复制代码 代码如下:

/*
   文件名:    HelloLua.h
   描 述:    Lua Demo
   创建人:    笨木头
   创建日期:   2012.12.24
*/ 

#ifndef __HELLO_LUA_H_
#define __HELLO_LUA_H_

#include "cocos2d.h"

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

using namespace cocos2d;

class HelloLua : public CCLayer {
public:
    CREATE_FUNC(HelloLua);
    virtual bool init();

    static CCScene* scene();
};

#endif

看到红色粗体的代码了吗?(旁白:在哪呢?在哪啊?)
在这:

复制代码 代码如下:

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

(旁白:你妹纸的…你不能先贴出来再问吗?~!)
 
记住了,Lua是C语言库,所以在C++中使用必须用extern “C”声明,让编译器知道。
有了这些,我们就能开始使用Lua了。
(旁白:等等,总感觉有点不对劲= =)
 
啊,对了,还少一样东西,不过这个不需要我们做了,那就是引入Lua的库,没有库,我们怎么包含头文件都没用。

不过没关系,Cocos2d-x本来就支持Lua,所以这一步我们省下了,为了保险起见,我在新建Demo项目的时候勾选了支持Lua。

建议大家首先能创建一个支持Lua的Cocos2d-x项目,并且能编译运行,然后再继续往下看~
(旁白:你就不能教我们引入Lua库么?= =)
 
我教?我不懂~

2. 开始使用

来看看我们的cpp文件,我们要开始使用Lua了~!

复制代码 代码如下:

#include "HelloLua.h"

CCScene* HelloLua::scene() {
    CCScene* scene = CCScene::create();
    CCLayer* layer = HelloLua::create();
    scene->addChild(layer);

    return scene;
}

bool HelloLua::init() {
    lua_State* pL = lua_open();
    luaopen_base(pL);
    luaopen_math(pL);
    luaopen_string(pL);

    /* 1.执行Lua脚本,返回0代表成功 */
    /* 2.重置栈顶索引 */
    /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
  /* 4.获取栈顶的值 */
  
    lua_close(pL);
    return true;
}

为了不一下子就一大堆代码吓坏大家,我把部分代码先删了,我们来看看现在这个代码的情况:
1) HelloLua是一个场景(旁白:废话…)
2) HelloLua有一个init函数(旁白:你妹纸的,进入正题好不?)
3) 我就喜欢旁白吐槽~(旁白:….)
4) 要使用Lua,首先要有一个lua_State,这是什么呢?我引用《游戏人工智能编程案例精粹》一书的一句话(191页):“每一个运行的脚本文件都在一个动态分配的叫做lua_State的数据结构中运行”。不明白的话,也没有关系,我们就把lua_State当成是一个Lua的身体,Lua在做任何事情的时候都不能没有身体。
5) 接下来看到几句话:luaopen_base(pL);luaopen_math(pL);luaopen_string(pL);
Lua有一些标准库,要使用这些库,就要用luaopen_**去加载这些库
6) 然后最后还有一句话:lua_close(pL),一看就知道了,用来释放内存的。
7) 旁白呢?(旁白:心情不好…不想吐槽)

3. 执行Lua脚本

现在我们来一步步完善我们的代码,执行Lua脚本很简单,看看:

复制代码 代码如下:

bool HelloLua::init() {
    lua_State* pL = lua_open();
    luaopen_base(pL);
    luaopen_math(pL);
    luaopen_string(pL);

    /* 1.执行Lua脚本,返回0代表成功 */
    int err = luaL_dofile(pL, "helloLua.lua");
    CCLOG("open : %d", err);

    /* 2.重置栈顶索引 */
    lua_settop(pL, 0);
    lua_getglobal(pL, "myName");

    /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
  /* 4.获取栈顶的值 */
  
    lua_close(pL);
    return true;
}

(旁白:不吐槽都不行了。。。你是不是把第2步也不小心放出来了?= =)
我们还要新建一个lua文件,很简单,新建一个文本文件,把后缀名改为lua就行了。现在我们来创建一个helloLua.lua文件:

复制代码 代码如下:

-- helloLua.lua文件
myName = "beauty girl"

 
(旁白:别老是忽略我好吧。。。第2步是怎么回事?!)
好,lua文件也有了,在C++中只要调用luaL_dofile就能执行lua脚本了,注意了,必须把lua_State也作为参数传给luaL_dofile,前面已经说了,身体不能少。

4. 重置栈顶索引, 将全局变量放到堆栈中

大家没有发现吗?我把第2步也放出来了~
(旁白:啊喂~!我说了好多次了,我发现了啊~!)
 
lua_settop(pL, 0);是为了确认让栈顶的索引置为0,因为我们操作栈的时候是根据索引来操作的。置0之后,我们入栈的第一个元素的索引就是1。

那,lua_getglobal(pL, “myName”);又是什么呢?咋一看好像是从lua中取得myName这个全局变量的值,但并不是这样的,虽然最终也是这样。
(旁白:你妹纸的,说清楚点)
 
我们之前说过了,Lua和C++是不能直接通信的,要通过堆栈来通信。
因此,lua_getglobal(pL, “myName”);只是把myName放到了栈中,然后lua就会通过myName去全局表寻找,找到myName对应的字符串“beauty girl”,再放到栈中。(第01章的时候介绍过的步骤,还记得吗?不记得的建议大家去看看~)
(旁白:停!让我缓冲一下…)
(旁白:
1.C++把myName放到堆栈
2.lua从堆栈取得myName
3.lua用myName去lua全局表查找获取myName对应的字符串,得到“beauty girl”字符串,然后再放回堆栈
4.最后C++就可以从堆栈中取得“beauty girl”字符串?
好~!明白了~)

5. 最后一步,C++取得字符串

我们来看看完整的代码:

复制代码 代码如下:

bool HelloLua::init() {
    lua_State* pL = lua_open();
    luaopen_base(pL);
    luaopen_math(pL);
    luaopen_string(pL);

    /* 1.执行Lua脚本,返回0代表成功 */
    int err = luaL_dofile(pL, "helloLua.lua");
    CCLOG("open : %d", err);

    /* 2.重置栈顶索引 */
    lua_settop(pL, 0);
    lua_getglobal(pL, "myName");

    /* 3.判断栈顶的值的类型是否为String, 返回非0值代表成功 */
    int isstr = lua_isstring(pL, 1);
    CCLOG("isstr = %d", isstr);

    /* 4.获取栈顶的值 */
    const char* str = lua_tostring(pL, 1);
    CCLOG("getStr = %s", str);

    lua_close(pL);
    return true;
}

lua_getglobal已经完成了很多工作了,现在堆栈上就放着“beauty girl”字符串,我们只要去取就可以了。
获取堆栈的值有很多种方法,分别对应不同的变量类型:

复制代码 代码如下:

lua_toboolean
lua_toNumber
lua_tocfunction
lua_tostring

我就不全部举例了,现在我们要用lua_tostring来获取栈顶的值。
最后,在AppDelegate.cpp中把默认启动场景设为我们的HelloLua场景,用调试模式运行项目,将看到以下日志:

复制代码 代码如下:

open : 0
isstr = 1
getStr = beauty girl

好,本章到此结…(旁白:等等!第3步是什么?你还没有解释啊,魂淡~!)
 
对了对了,Lua还提供了很多函数供我们判断堆栈中的变量类型,比如lua_isstring、lua_isnumber等等,和lua_tostring等函数是对应的。返回非0值表示类型正确。
一般在取值之前都要判断一下,不能程序很可能意外崩溃~!
(旁白:吓 = =!)
 
好~本章到此结束~

6. 赠送的

最后再告诉大家一个笑眯眯~
那就是用lua_pop(pL, 1); 可以清除指定堆栈上的数据~
噗,闪人~
(旁白:我帮他解释一下。。。是小秘密。。。不是笑眯眯= =)

时间: 2024-10-14 18:43:09

Lua和C++的通信流程代码实例_Lua的相关文章

Lua和C++的通信流程分解_Lua

网上关于Lua的教程似乎还没有泛滥,最近刚好学习在Cocos2d-x使用Lua,当然了,我是写教程狂,我会分享我的学习心得的~ (旁白:我噗~!每次你写东西我就要吐槽,你不累么= =)   这是第一课,先来让Lua和C++认识一下,顺便让它们逛街吃饭牵小手什么的- (旁白:...吹,继续吹) 1. Lua的堆栈和全局表 我们来简单解释一下Lua的堆栈和全局表,堆栈大家应该会比较熟悉,它主要是用来让C++和Lua通信的,是的,它们并不认识对方,只能通过堆栈来沟通,就像写信一样. (旁白:它们不会用

Lua中的类编程代码实例_Lua

Lua的类有点像javascript,但是更简明灵活,table即对象,对象就是类.Metatables比起ruby里的MetaClass更加好用,缺点是实例化和继承的代码有点多, 不像ruby里的"<"和"<<",继承链就是查找方法时的方法链. Account={ test1=function(a) print("Account test1") end } Account.test2=function(a) print(&qu

Lua之协同程序coroutine代码实例_Lua

do --create coroutine table --coroutine state: suspended, running, dead, normal --when create the coroutine, the status is suspended, After calling it, the status is dead --get the coroutine status by the way coroutine.status local coA = 0; local coB

Lua多重继承代码实例_Lua

local function search(k, plist) for i, v in pairs(plist) do local temp_v = v[k] if temp_v then return temp_v end end end function createClass(...) local c = {} local parents = {...} --父类列表中搜索方法 setmetatable(c, { __index = function(t, k) return search

Lua中的函数代码实例_Lua

在lua中,函数是一种"第一类值",它们具有特定的词法域. 第一类值:表示在lua中,函数与其他传统类型的值(数字和字符串)具有相同的权利,函数可以存储到变量中(无论全局变量还是局部变量)或者是table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值. 词法域:是指一个函数可以嵌套在另一个函数中.内部的函数可以访问外部函数中的变量. 看例子代码: 复制代码 代码如下: do       function foo(a, b, c)          print(a, b, c

Lua中遍历文件操作代码实例_Lua

写的一个关于遍历文件的程序段  记录一下咯 --[[检查所有.txt文件 比如A.txt中第一行规定有20列,但是在X行中多输入一个Tab,则输出:A表的X行填写不规范,行末有多余填写 ]] getinfo = io.popen('dir ..//file /b /s') all = getinfo:read('*all') local filenameList = io.open("filename.txt", "wb") filenameList:write(&

获取Lua表结构(table)数据实例_Lua

只是获取一个全局变量什么的太没意思了,今天我们来玩个高难度的--获取Lua表结构的数据. (旁白:O O!我是不是该说点什么?) 上一章传送门:http://www.jb51.net/article/55093.htm 1. 什么是table table是Lua里最强大的数据类型,我们可以当成是数组,但是它又和数组有点不一样,建议大家看看Lua的语法教程,因为我对table也没有熟悉到可以给大家解释的程度. (旁白:那你还写什么教程...) 2. 获取table变量 现在,我们给helloLua

Openresty服务器使用lua脚本写的Hello World简单实例_Lua

Openresty提供了丰富的接口和变量给Lua,开发者可以充分利用Lua语言特性和这些接口进行高效率开发.万事开头难,但是对于编程来说能写出Hello world就已经算是成功一半了. 1.安装openresty 2.配置nginx 复制代码 代码如下: server {      listen 80;      server_name localhost;        #charset koi8-r;        #access_log logs/host.access.log main

Lua与C语言间的交互实例_Lua

Lua 是一门轻巧.灵活.扩展性很强的脚本语言,它可以很容易的嵌入到其他语言(C/C++)中使用,这主要得益于其提供了功能强大的 C API,这让其跟 C/C++ 间的互调成为一件很轻松的事. Lua 调用 C Lua 调用 C 函数,其实就是把 C 函数注册到 Lua 中去,把 C 函数地址传递给 Lua 解释器.这个传递是要遵循一个的协议的,即: 复制代码 代码如下: typedef int (*lua_CFunction)(lua_State* L) Lua 和 C 是通过栈(State)