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" ...
随机推荐
- string源码实现分析
最近写hashtable的实现的时候用模板类的思想,在普通int,long,double类型的时候测试时没问题的,当用到string的时候,一直有问题. 实现的equal函数是比较粗暴的使用两者所有对 ...
- Unit07: MyBatis框架简介 、 MyBatis基本应用
Unit07: MyBatis框架简介 . MyBatis基本应用 1. myBatis (1)myBatis是什么? 是一个开源的持久层框架. 注:myBatis底层仍然是jdbc. (2)编程步骤 ...
- 安装ecb
mac emacs上安装ecb,通过elpa折腾得要死,死活无法使用. 解决办法:下载https://github.com/alexott/ecb,添加路径,(require 'ecb),直接ok.
- 第二章 伪分布式安装hadoop hbase
安装单机模式的hadoop无须配置,在这种方式下,hadoop被认为是一个单独的java进程,这种方式经常用来调试.所以我们讲下伪分布式安装hadoop. 我们继续上一章继续讲解,安装完先试试SSH装 ...
- 【BZOJ】2657: [Zjoi2012]旅游(journey)(树的直径)
题目 传送门:QWQ 分析 在任意两个不相邻的点连一条线,求这条线能穿过几个三角形. 建图比较讲究(详见代码) 求树的直径. 代码 #include <bits/stdc++.h> usi ...
- Linux 利用hosts.deny 防止暴力破解ssh
一.ssh暴力破解 利用专业的破解程序,配合密码字典.登陆用户名,尝试登陆服务器,来进行破解密码,此方法,虽慢,但却很有效果. 二.暴力破解演示 2.1.基础环境:2台linux主机(centos 7 ...
- angularJS开发时用到的命令
node --version && npm --version 查看nodejs版本号和npm版本号 yo --version && bower --version & ...
- SVN目录结构
整理了一下svn目录结构,如下: 项目名称 ----branches 软件产品的迭代开发版本 ----tags 软件产品经过完整测试的历史稳定版本,已部署在客户机器上使用的 --- ...
- git commit时候出现的问题
git commit 提交的时候,出现*** Please tell me who you are. git config --global ...问题 1 $ git commit -a -m 'v ...
- numpy的通用函数
通用函数:快速的元素级数组函数 通用函数是一种对ndarry中的数据执行元素级运算的函数,可以看作是简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化包装器. 一元func: abs丶f ...