Lua与C交换
1.C调用Lua函数
(1) 首先要进行Lua的初始化,这个主要是lua_open和luaL_openlibs函数
(2)然后是解析并编译lua的代码,这个主要是luaL_dofile函数
(3) 解析好之后使用lua_getglobal指明要调用的lua函数
(4) 如果有lua函数的参数,通过使用lua_pushstring函数传递参数
(5) 最后调用lua_pcall进行lua函数的调用
(6) 调用完成之后采用lua_tonumber类函数可以获取到函数的返回结果
2.Lua调用C函数
(1) 在Lua中调用C的函数,该函数必须进行注册,这个通过lua_register这个函数来完成
(2) 在Lua中调用注册的函数,会调用上面注册的函数(类似于回调),所有的处理在这个函数里面
(3) 这个函数里面可以使用lua_tostring类函数来获取函数的参数
(4) 如果有返回值,通过lua_pushnumber这个函数来返回。
3.例子
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
} #include <iostream>
#include <string>
using namespace std; int main()
{
//Lua示例代码
char *szLua_code =
"r = string.gsub(c_Str, c_Mode, c_Tag) --宿主给的变量 "
"u = string.upper(r)";
//Lua的字符串模式
char *szMode = "(%w+)%s*=%s*(%w+)";
//要处理的字符串
char *szStr = "key1 = value1 key2 = value2";
//目标字符串模式
char *szTag = "<%1>%2</%1>"; lua_State *L = luaL_newstate();
luaL_openlibs(L); //把一个数据送给Lua
lua_pushstring(L, szMode);
lua_setglobal(L, "c_Mode");
lua_pushstring(L, szTag);
lua_setglobal(L, "c_Tag");
lua_pushstring(L, szStr);
lua_setglobal(L, "c_Str"); //执行
bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code),
"demo") || lua_pcall(L, , , );
if(err)
{
//如果错误,显示
cerr << lua_tostring(L, -);
//弹出栈顶的这个错误信息
lua_pop(L, );
}
else
{
//Lua执行后取得全局变量的值
lua_getglobal(L, "r");
cout << "r = " << lua_tostring(L,-) << endl;
lua_pop(L, ); lua_getglobal(L, "u");
cout << "u = " << lua_tostring(L,-) << endl;
lua_pop(L, );
}
lua_close(L);
return ;
}
这段代码把字符串中的key=value字符串全部转换成XML格式<key>value</key>,在这个例子中,C++程序通过调用lua_pushstring把C字符串压入栈顶,lua_setglobal的作用是把栈顶的数据传到Lua环境中作为全局变量。执行代码完成后,使用lua_getglobal从Lua环境中取得全局变量压入栈顶,然后使用lua_tostring把栈顶的数据转成字符串。由于lua_tostring本身没有出栈功能,所以为了平衡(即调用前与调用后栈里的数据量不变),使用lua_pop弹出由lua_setglobal压入的数据。
从上面的例子可以看出,C++和Lua之间一直围绕着栈在转,可见栈是极为重要的。有必要列出一些Lua C API中的主要栈操作先,它们的作用直接可以从函数名中看出。
3.1 压入元素到栈里
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
void lua_pushcfunction (lua_State *L, lua_CFunction fn);
3.2 查询栈里的元素
lua_isnil (lua_State *L, int index);
lua_isboolean (lua_State *L, int index);
int lua_isnumber (lua_State *L, int index);
int lua_isstring (lua_State *L, int index);
int lua_isfunction (lua_State *L, int index);
int lua_istable (lua_State *L, int index);
int lua_isuserdata (lua_State *L, int index);
lua_islightuserdata (lua_State *L, int index);
lua_isthread (lua_State *L, int index);
3.3 转换栈里的元素
int lua_toboolean (lua_State *L, int index);
double lua_tonumber (lua_State *L, int index);
const char * lua_tostring (lua_State *L, int index);
const char * lua_tolstring (lua_State *L, int idx, size_t *len);
size_t lua_strlen (lua_State *L, int index);
lua_CFunction lua_tocfunction (lua_State *L, int idx);
void * lua_touserdata (lua_State *L, int idx);
lua_State * lua_tothread (lua_State *L, int idx);
3.4 Lua栈的维护
int lua_gettop (lua_State *L); //取得栈顶元素的索引,即栈中元素的个数
void lua_settop (lua_State *L, int index); //设置栈顶索引,即设置栈中元素的个数,如果index<0,则从栈顶往下数,下同
void lua_pushvalue (lua_State *L, int index); //把栈中指定索引的元素复制一份到栈顶
void lua_remove (lua_State *L, int index); //删除指定索引的元素
void lua_insert (lua_State *L, int index); //移动栈顶元素到指定索引的位置,栈中数目没有改变
void lua_replace (lua_State *L, int index); //从栈顶弹出元素值并将其设置到指定索引位置,栈中的数目减一
int lua_checkstack (lua_State *L, int extra); //确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈。
int lua_pop(L,n); //从栈顶弹出n个元素,它是一个lua_settop的包装:#define lua_pop(L,n) lua_settop(L, -(n)-1)
3.5 表的操作
上面的列表中并没有lua_pushtable和lua_totable,那么怎样取得或设置Lua中的table数据呢?
在Lua中,table是一个很重要的数据类型,在table中不仅可以象C中的数据一样放一组数据,还可以象map一样以key=value的方式存放数据,如Lua代码中的:
tb = {"abc",12,true,x=10,y=20,z=30}
前三个数据可以用tb[1]~tb[3]取得,而后三个数据通过tb.x, tb.y, tb.z取得,尽管看起来很牛叉,不过剥开神奇的外衣,实际上Lua的table中,所有的数据都是以key=value的形式存放的,这句Lua代码也可以写成:
tb = {[1]="abc", [2]=12, [3] = true, ["x"]=10, ["y"]=20, ["z"]=30}
它的形式就是[key]=value,所谓的tb.x只是tb["x"]的语法糖而已,如果愿意,也可以用tb["x"]取得这个数据10。我们把上面的例子改成使用表的
...
int main()
{
//Lua示例代码,使用table
char *szLua_code =
"x = {} --用于存放结果的table "
"x[1],x[2] = string.gsub(c.Str, c.Mode, c.Tag) --x[1]里是结果,x[2]里是替换次数 "
"x.u = string.upper(x[1])";
//Lua的字符串模式
char *szMode = "(%w+)%s*=%s*(%w+)";
//要处理的字符串
char *szStr = "key1 = value1 key2 = value2";
//目标字符串模式
char *szTag = "<%1>%2</%1>"; lua_State *L = luaL_newstate();
luaL_openlibs(L); //把一个tabele送给Lua
lua_newtable(L); //新建一个table并压入栈顶
lua_pushstring(L, "Mode");// key
lua_pushstring(L, szMode);// value
//设置newtable[Mode]=szMode
//由于上面两次压栈,现在table元素排在栈顶往下数第三的位置
lua_settable(L, -);
//lua_settable会自己弹出上面压入的key和value lua_pushstring(L, "Tag");// key
lua_pushstring(L, szTag);// value
lua_settable(L, -); //设置newtable[Tag]=szTag lua_pushstring(L, "Str");// key
lua_pushstring(L, szStr);// value
lua_settable(L, -); //设置newtable[Str]=szStr lua_setglobal(L,"c"); //将栈顶元素(newtable)置为Lua中的全局变量c //执行
bool err = luaL_loadbuffer(L, szLua_code, strlen(szLua_code),
"demo") || lua_pcall(L, , , );
if(err)
{
//如果错误,显示
cerr << lua_tostring(L, -);
//弹出栈顶的这个错误信息
lua_pop(L, );
}
else
{
//Lua执行后取得全局变量的值
lua_getglobal(L, "x"); //这个x应该是个table
if(lua_istable(L,-))
{
//取得x.u,即x["u"]
lua_pushstring(L,"u"); //key
//由于这次压栈,x处于栈顶第二位置
lua_gettable(L,-);
//lua_gettable会弹出上面压入的key,然后把对应的value压入
//取得数据,然后从栈中弹出这个value
cout << "x.u = " << lua_tostring(L,-) << endl;
lua_pop(L, ); //取得x[1]和x[2]
for(int i=; i<=; i++)
{
//除了key是数字外,与上面的没什么区别
lua_pushnumber(L,i);
lua_gettable(L,-);
cout << "x[" << i <<"] = " << lua_tostring(L,-) << endl;
lua_pop(L, );
}
} //弹出栈顶的x
lua_pop(L, );
}
lua_close(L);
return ;
}
本例中用到的新Lua C API是:
void lua_newtable (lua_State *L); //新建一个空的table并压入栈顶。
void lua_settable (lua_State *L, int idx); //lua_settable以table在栈中的索引作为参数,并将栈顶的key和value出栈,用这两个值修改table。
void lua_gettable (lua_State *L, int idx); //lua_gettable以table在栈中的索引作为参数,弹出栈顶的元素作为key,返回与key对应的value并压入栈顶。最后,Lua告别针对table提供了存取函数
void lua_rawgeti (lua_State *L, int idx, int n); //取得table[n]并放到栈顶,上例中69-70行的lua_pushnumber(L,i);lua_gettable(L,-2);可以用lua_rawgeti(L,-1)代替。
lua_getfield (lua_State *L, int idx, const char *k); //取得table.k并放到栈顶,上例中57-59行的lua_pushstring(L,"u");lua_gettable(L,-2);可以替换成lua_getfield(L,-1,"u")。
void lua_setfield (lua_State *L, int idx, const char *k); //把栈顶的数据作为value放入table.k中,上例中的形如lua_pushstring(L, "key");lua_pushstring(L, value);lua_settable(L,-3);可以改成lua_pushstring(L,value);lua_setfield(L,-2,"key");的形式。
void lua_rawseti (lua_State *L, int idx, int n); //把栈顶的数据作为value放入table[n]中
Lua与C交换的更多相关文章
- Lua 与C 交换 第一篇
编译 windows上编译lua源代码 cl /MD /O2 /W3 /c /DLUA_BUILD_AS_DLL *.c del *.o ren lua.obj lua.o ren luac.obj ...
- Lua的线程和状态
[那不是真的多线程] Lua不支持真正的多线程,这句话我在<Lua中的协同程序>这篇文章中就已经说了.根据我的编程经验,在开发过程中,如果可以避免使用线程,那就坚决不用线程,如果实在没有更 ...
- tolua 有些功能可以用(经过测试)
tolua 提供几个 C++ 与 Lua 进行数据交换的工具函数. ~~ tolua.type 返回一个 C++ 对象的类型描写叙述字符串. local node = display.newNode( ...
- 如何在Lua与C/C++之间实现table数据的交换
之前在<C/C++和Lua是如何进行通信的?>一文中简单的介绍了lua与宿主之间的通信.简单的说两种不同的语言之间数据类型不一样又如何进行数据交换呢?那就是lua_State虚拟栈,通过栈 ...
- Lua 学习笔记(九)协同程序(线程thread)
协同程序与线程thread差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和命令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区别在于,一个具有多个线程的 ...
- Lua 协程coroutine
协程和一般多线程的区别是,一般多线程由系统决定该哪个线程执行,是抢占式的,而协程是由每个线程自己决定自己什么时候不执行,并把执行权主动交给下一个线程. 协程是用户空间线程,操作系统其存在一无所知,所以 ...
- wrapper for lua
考虑使用已经有的dll,要写wrapper,使得在lua中能调用dll里的函数,嗯,参考<Programming in lua>,然后仿写luars232. 一.函数定义 先分析一个函数的 ...
- lua 学习
尽管所有的脚本语言在特定领域都有自己的一席之地,但在游戏开发的世界里,Python 和 Lua 是非常适合的,因为它们可以直接调用C++的功能. lua最让人惊喜的地方应该是它的执行速度,目前没有任何 ...
- 《Lua程序设计 第二版》学习笔记一
Lua简介 Lua是一种简单.可拓展.可移植及高效的脚本语言. 开始 Lua之间不需要分隔符 运行方式: Linux下: lua -i prog dofile("lib1.lua" ...
随机推荐
- 算法题:求一个序列S中所有包含T的子序列(distinct sub sequence)
题: 给定一个序列S以及它的一个子序列T,求S的所有包含T的子序列.例: S = [1, 2, 3, 2, 4] T = [1, 2, 4] 则S的所有包含T的子序列为: [1, 2, 3, 2, 4 ...
- JDK 8 新特性
JDK 8, Oracle's implementation of Java SE 8. JDK 8 是 Oracle 对 Java SE 8 规范的实现. 本文分析 JDK 8 引入的新特性. 官方 ...
- [Java][Web]Request 实现转发和 MVC 设计模式
String data = "aaaaa"; request.setAttribute("data",data); // 将数据存在 request reque ...
- Log4j.xml配置(rolling示例)
Log4j.xml配置(很详细) <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4 ...
- ES6中的新特性
本人最近学习es6一些方法,难免有些手痒,想着能不能将这些方法总结下,如下 1.数组的扩展 1)首先什么是伪数组 无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以对真正数组遍历方法 ...
- 第四章 istio快速入门(快速安装)
4.1 环境介绍 K8s 1.9 以上版本. 4.2 快速部署Istio 下载: https://github.com/istio/istio/releases/, 下载 1.1.0-snapsh ...
- StringsUtil字符串工具类---灵活截取
package com.js.ai.modules.pointwall.interfac; import javax.print.attribute.standard.MediaName; publi ...
- 防火墙启动失败,提示最后一行出错【COMMIT】
使用 /etc/init.d/iptables save 后 iptables配置文件发生变化 并生成iptables.save vim iptables.save [配置内容则是原来的] s ...
- wget 技巧
最近用到一个命令wget,有一个技巧分享一下. [root@py ~]# wget -m -k http://www.example.com 可以将示例网站整个打包,作为本地镜像.
- MonkeyScript测试命令集合
MonkeyScript:(不支持截屏) 可以被Monkey识别的集合命令 可以完成重复固定的操作 MonkeyRunner(支持截屏操作) 提供一系列API,可以完成模拟事件和截屏操作 Mo ...