C与Lua互相调用的时候,栈变化分析
1 C调用Lua函数的堆栈变化
例子
Lua文件中的函数
function testNewCounter2() return "第四个结果" end C中的例子
void t_new(lua_State *aaa){ } lua_pushstring(aaa, "feifei"); lua_pushcfunction(aaa, t_new);
const char *ccc= lua_tostring(aaa, -); printf("倒数第二个的值为%s\n",ccc); lua_getglobal(aaa, "testNewCounter2"); int iiiiif=lua_gettop(aaa); printf("现在栈内得数目=%d\n",iiiiif); lua_pcall(aaa, , , ); int iiiii=lua_gettop(aaa); printf("执行函数之后现在栈内得数目=%d\n",iiiii); const char *ccfffc= lua_tostring(aaa, -);//倒数第三个 const char *ccfffc2= lua_tostring(aaa, -);//倒数第一个,也就是lua函数的返回值 printf("倒数第三个=%s\n",ccfffc); printf("倒数第一个,也就是lua函数的返回值=%s\n",ccfffc2);
运行结果如下:
倒数第二个的值为feifei
现在栈内得数目=3
执行函数之后现在栈内得数目=3
倒数第三个=feifei
倒数第一个,也就是lua函数的返回值=第四个结果
也就是说函数执行完了之后,首先是把自身弹出,然后把返回结果压住栈内,
而在函数压入之前的,比如feifei等,函数控制不了,也不会把他们弹出
下面给lua函数加一个参数试试,也就是lua文件的函数为
function testNewCounter2(para) return "第四个结果” .. para end lua_pushstring(aaa, "feifei"); lua_pushcfunction(aaa, t_new); const char *ccc= lua_tostring(aaa, -); printf("倒数第二个的值为%s\n",ccc); lua_getglobal(aaa, "testNewCounter2"); lua_pushstring(aaa, "lua的参数"); int iiiiif=lua_gettop(aaa); printf("现在栈内得数目=%d\n",iiiiif); lua_pcall(aaa, , , ); int iiiii=lua_gettop(aaa); printf("执行函数之后现在栈内得数目=%d\n",iiiii); const char *ccfffc= lua_tostring(aaa, -);//倒数第三个 const char *ccfffc2= lua_tostring(aaa, -);//倒数第一个,也就是lua函数的返回值 printf("倒数第三个=%s\n",ccfffc); printf("倒数第一个,也就是lua函数的返回值=%s\n",ccfffc2);
返回结果:
倒数第二个的值为feifei
现在栈内得数目=4
执行函数之后现在栈内得数目=3
倒数第三个=feifei
倒数第一个,也就是lua函数的返回值=第四个结果lua的参数
和预期的一样,lua函数在执行完之后,会吧他自身和他的参数弹出,然后把返回结果压入栈中
2 Lua调用C函数的堆栈变化
首先lua文件中函数为 function testNewCounter2(para)
ccc=new222()
end c文件中的函数
int t_new(lua_State *aaa){ int ffdsfdsf=lua_gettop(aaa ); printf("函数私有栈的数目=%d\n",ffdsfdsf); lua_pushstring(aaa, "C函数的结果"); int ffdsfdsffds=lua_gettop(aaa); printf("加入一个结果之后的函数私有栈的数目=%d\n",ffdsfdsffds); return ; }
备注:这里需要说明的一点是返回值为1,说明就一个返回结果,表示压入栈中的返回值数量。因此这个函数无需在压住结果之前清空栈,在他返回后,Lua会自动删除栈中结果之下的内容,就是说不管你加入几个元素进栈,只看返回结果,返回结果是几,就把几个加入到全局栈,其余的会清空,在函数返回完毕之后,函数内的私有栈也全部清空,在最后一步return数目的时候,确实是加入到了全局栈,而函数开始的时候,获取的参数第一个始终是传过来的参数,而不是全局栈中最顶上一个元素,这一点要区分开
调用代码如下:
lua_pushstring(aaa, "feifei"); lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, t_new); lua_setglobal(aaa, "new222"); lua_getglobal(aaa, "testNewCounter2"); lua_pcall(aaa, , , ); const char *ccc= lua_tostring(aaa, -); printf("执行完函数之后倒数第一个=%s\n",ccc); const char *ccc2= lua_tostring(aaa, -); printf("执行完函数之后倒数第二个=%s\n",ccc);
结果:
函数私有栈的数目=0
加入一个结果之后的函数私有栈的数目=1
执行完函数之后倒数第一个=wenqian
执行完函数之后倒数第二个=feifei
首先来看 t_new函数里面有一个私有栈,不受外部影响,他的栈里面就是传给他的参数。
然后看调用代码,第一和第二是加入两个字符串,然后注册t_new,然后调用
testNewcounter2,调用玩之后,栈弹出这个函数,因为函数没有返回值,所以此时栈内有两个,就是开始加入的两个字符串。
下面再看看让testNewCounter2返回结果时候的调用
这里只是修改lua文件中的方法,改为:
function testNewCounter2( ) ccc=new222() return "返回new222的结果" .. ccc end
开始调用
lua_pushstring(aaa, "feifei"); lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, t_new); lua_setglobal(aaa, "new222"); lua_getglobal(aaa, "testNewCounter2"); lua_pcall(aaa, , , ); const char *ccc= lua_tostring(aaa, -); printf("执行完函数之后倒数第一个=%s\n",ccc); const char *ccc2= lua_tostring(aaa, -); printf("执行完函数之后倒数第二个=%s\n",ccc2);
结果:
函数私有栈的数目=0
加入一个结果之后的函数私有栈的数目=1
执行完函数之后倒数第一个=返回new222的结果C函数的结果
执行完函数之后倒数第二个=wenqian
倒数第一个成了new222返回的结果,和预期的一样
Lua和c的交互中还有一个比较难理解的地方就是upvalue。upvalue实现了一种类似于C语言中静态变量的机制,这种变量只在一个特定的函数中可见。每当在Lua中创建一个函数时,都可以将任意数量的upvalue与这个函数相关联。每个upvalue都可以保存一个lua值。以后,在调用这个函数时,就可以通过伪索引来访问这些upvalue了
closure可以用一个函数代码来创建多个closure,每个closure可以拥有不同的upvalue。
下面得例子,在c语言中创建一个newCounter函数。这个函数是一个工厂函数,每次调用都返回一个新的账户函数
int newCounter(lua_State *aaa){ lua_pushinteger(aaa, ); lua_pushcclosure(aaa, &counter, ); int fff=lua_gettop(aaa); printf("推入了closure之后,站内的数量=%d",fff); return ; } static int counter(lua_State *aaa){ int val=(int)lua_tointeger(aaa, lua_upvalueindex()); int fdsfdsf= lua_gettop(aaa); printf("每次进入时栈的数量=%d",fdsfdsf); lua_pushinteger(aaa, ++val); lua_pushvalue(aaa, -); lua_replace(aaa, lua_upvalueindex()); int fdsfdsf11fds1= (int)lua_gettop(aaa); printf("最后栈的数量=%d",fdsfdsf); return ; } 在Lua文件中,函数如下:
function newCounterFactory() counterFun=newCounter(); return counterFun() end function newCounterFactoryAgain() return counterFun() end C语言调用代码如下:
lua_pushstring(aaa, "feifei"); lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, newCounter); lua_setglobal(aaa, "newCounter"); lua_getglobal(aaa, "newCounterFactory"); lua_pcall(aaa, , , ); const char *ccc= lua_tostring(aaa, -); printf("第一次调用倒数第一个值=%s\n",ccc); const char *ccc22= lua_tostring(aaa, -); printf("第一次调用倒数第二个值=%s\n",ccc22); lua_getglobal(aaa, "newCounterFactoryAgain"); lua_pcall(aaa, , , ); const char *ccccc= lua_tostring(aaa, -); printf("第二次调用倒数第一个值=%s\n",ccccc); const char *ccccc2= lua_tostring(aaa, -); printf("第二次调用倒数第二个值=%s\n",ccccc2); const char *ccccc3= lua_tostring(aaa, -); printf("第二次调用倒数第三个值=%s\n",ccccc3);
运行结果:
推入了closure之后,站内的数量=1
每次进入时栈的数量=0
最后栈的数量=1
第一次调用倒数第一个值=1
第一次调用倒数第二个值=wenqian
每次进入时栈的数量=0
最后栈的数量=1
第二次调用倒数第一个值=2
第二次调用倒数第二个值=1
第二次调用倒数第三个值=wenqian
从第二次调用可以看出,每一次counter()调用完了之后,确实是加入到了全局栈
现在分析 一下特殊情况
第一:修改一下lua函数,让newCounterFactory只是返回counter函数,而不执行,如下: function newCounterFactory()
counterFun=newCounter();
return counterFun
end
执行代码如下:
lua_pushstring(aaa, "feifei");
lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, newCounter);
lua_setglobal(aaa, "newCounter");
lua_getglobal(aaa, "newCounterFactory");
lua_pcall(aaa, ,, ); auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -);
printf("是不是函数:%d\n",ffdsfdsfdsfdsfff);
// lua_pcall(aaa, 0,1, 0); const char *ccc= lua_tostring(aaa, -);
printf("第一次调用倒数第一个值=%s\n",ccc);
const char *ccc22= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22);
const char *ccc22222= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22222);
运行结果:
推入了closure之后,站内的数量=1
是不是函数:1
第一次调用倒数第一个值=(null)
第一次调用倒数第二个值=wenqian
第一次调用倒数第二个值=feifei
分析得知,newCounter没有执行,因为newCounterFactory()只是返回了他,并把它加入了全局栈中,所以全局栈中第一个是
function。
那么我们现在我们知道现在newCounter函数是位于全局栈的顶部,那么我们可以执行一下他,调用代码如下:
lua_pushstring(aaa, "feifei");
lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, newCounter);
lua_setglobal(aaa, "newCounter");
lua_getglobal(aaa, "newCounterFactory");
lua_pcall(aaa, ,, ); auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -);
printf("是不是函数:%d\n",ffdsfdsfdsfdsfff);
—-执行以下栈顶函数
lua_pcall(aaa, ,, ); const char *ccc= lua_tostring(aaa, -);
printf("第一次调用倒数第一个值=%s\n",ccc);
const char *ccc22= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22);
const char *ccc22222= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22222);
运行结果如下:
推入了closure之后,站内的数量=1
是不是函数:1
每次进入时栈的数量=0
最后栈的数量=1
第一次调用倒数第一个值=1
第一次调用倒数第二个值=wenqian
第一次调用倒数第二个值=feifei
newCounter函数执行完毕,把他的参数和他自己出栈,然后压入他的返回值
那么返过来再看看最初的执行情况,就是newCounterFactory函数里面直接执行newCounter,这里在运行一遍结果
首先改一下lua代码
function newCounterFactory()
counterFun=newCounter();
-- return counterFun
return counterFun()
end
调用代码如下:
lua_pushstring(aaa, "feifei");
lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, newCounter);
lua_setglobal(aaa, "newCounter");
lua_getglobal(aaa, "newCounterFactory");
lua_pcall(aaa, ,, ); auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -);
printf("是不是函数:%d\n",ffdsfdsfdsfdsfff); const char *ccc= lua_tostring(aaa, -);
printf("第一次调用倒数第一个值=%s\n",ccc);
const char *ccc22= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22);
const char *ccc22222= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22222);
运行结果: 推入了closure之后,站内的数量=1
每次进入时栈的数量=0
最后栈的数量=1
是不是函数:0
第一次调用倒数第一个值=1
第一次调用倒数第二个值=wenqian
第一次调用倒数第二个值=feifei
和上个例子是一样得,只不过前者是在C里面执行了newCounter,而后者是在lua里面执行的,我认为他们都是一样的,虽然执行完了这个函数就出栈了,
在C语言中无法再次执行了,但是因为在lua中保存了他的一个引用【在哪里引用的?当newCounter执行过程中,lua_pushcclosure讲一个新的
closure留在了栈上,并以此作为newCounter的返回值,而在lua中的全局变量counterFun引用了他的返回值】,所以依然可以再次调用。
下面再看最后一种情况,验证函数里面加入栈的元素,到底对全局栈有什么影响
lua函数如下:
function newCounterFactory()
counterFun=newCounter();
return counterFun
--return counterFun()
end
C中newCounter方法
int newCounter(lua_State *aaa){ lua_pushstring(aaa, "");
lua_pushstring(aaa, "");
lua_pushinteger(aaa, );
lua_pushcclosure(aaa, &counter, );
int fff=lua_gettop(aaa);
printf("推入了closure之后,站内的数量=%d\n",fff);
return ;
}
在这里,我们多推入了几个元素,但是还是返回一个
调用代码如下:
lua_pushstring(aaa, "feifei");
lua_pushstring(aaa, "wenqian"); lua_pushcfunction(aaa, newCounter);
lua_setglobal(aaa, "newCounter");
lua_getglobal(aaa, "newCounterFactory");
lua_pcall(aaa, ,, ); auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -);
printf("是不是函数:%d\n",ffdsfdsfdsfdsfff); const char *ccc= lua_tostring(aaa, -);
printf("第一次调用倒数第一个值=%s\n",ccc);
const char *ccc22= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22);
const char *ccc22222= lua_tostring(aaa, -);
printf("第一次调用倒数第二个值=%s\n",ccc22222);
运行结果:
推入了closure之后,站内的数量=3
是不是函数:1
第一次调用倒数第一个值=(null)
第一次调用倒数第二个值=wenqian
第一次调用倒数第二个值=feifei
可以看到函数内入栈数目取决于返回值,返回值是几,就入栈几个,加到之前全局栈里面元素的上面,函数内其余的元素都会清除,而函数本身的私有栈也是全部清空了,
通过每次运行函数,在里面调用lua_gettop可以看得出来,私有栈不受全局栈影响,他的第一个参数永远是传入方法的第一个参数,而不是全局栈顶部的元素
C与Lua互相调用的时候,栈变化分析的更多相关文章
- lua如何调用C++函数
第一步是定义函数.所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用: typedef int (*lua_CFunction) (lua_State *L); 换句话说,函数必须要以Lu ...
- LUA脚本调用C场景,使用C API访问脚本构造的表
LUA调用C lua解析中集成了一些系统服务, 故脚本中可以访问系统资源, 例如, lua脚本可以调用文件系统接口, 可以调用数学库, 但是总存在一些lua脚本中访问不到的系统服务或者扩展功能, 如果 ...
- Lua中调用C函数
Lua利用一个虚拟的堆栈来给C传递值或从C获取值.每当Lua调用C函数,都会获得一个新的堆栈,该堆栈初始包含所有的调用C函数所需要的参数值(Lua传给C函数的调用实参),并且C函数执行完毕后,会把返回 ...
- tolua++实现lua层调用c++技术分析
tolua++技术分析 cocos2dx+lua 前言 一直都使用 cocos2dx + lua 进行游戏开发,用 Lua 开发可以专注于游戏逻辑的实现,另外一方面可以实现热更新:而且 lua 是一个 ...
- Lua中调用C函数(lua-5.2.3)
Lua能够调用C函数的能力将极大的提高Lua的可扩展性和可用性. 对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们全然能够通过C函数来实现,之后再通过Lua调用指定的C函数. 对于那些可 ...
- 深入xLua实现原理之Lua如何调用C#
xLua是腾讯的一个开源项目,为Unity. .Net. Mono等C#环境增加Lua脚本编程的能力.本文主要是探讨xLua下Lua调用C#的实现原理. Lua与C#数据通信机制 无论是Lua调用C# ...
- 原生实现C#和Lua相互调用-Unity3D可用
引言 本篇简单介绍如何在C#中执行Lua脚本,传递数据到Lua中使用,以及Lua中调用C#导出的方法等.在Unity中开发测试,并打IL2CPP的Android包在模拟器上运行通过.Lua版本 ...
- Lua中“.”调用方法与“:”调用方法的区别
Lua中“.”调用方法与“:”调用方法的区别: ...
- Lua中调用C++方法
目前项目,使用了Lua脚本,至于使用Lua的好处不再赘述了.于是对Tolua做了一些小小的学习,总结一下吧. 主要说一下如何在Lua中调用C++方法. Lua调用C++的桥梁,是tolua.tolua ...
随机推荐
- js判断输入框的范围,并且只能输入数字
<input type="text" onkeyup="javascript:this.value=this.value.replace(/[^\d]/g,''); ...
- SSH_框架整合4--添加员工信息
SSH_框架整合4--添加员工信息 一. 1 index.jsp:添加:<a href="emp-input">添加员工向信息:Add Employees' Infor ...
- 战胜忧虑<3>——学会接受不可避免的事实。
学会接受不可避免的事实. 对必然的事情愉快地承受,就像杨柳承受风雨,水接受一切容器,我们也要承受一切事实. 故事: 在美国庆祝陆军在北非获胜的那一天,我接到国防部送来的一封电报,我的侄儿——我最爱的一 ...
- Erlang库 -- 有意思的库汇总
抄自这里 首先,库存在的目的大致可分为:1.提供便利2.尽可能解决一些痛点 首先,我们先明确一下Erlang编程语言的一些痛点(伪痛点):1,单进程问题Erlang虚拟机属于抢占式调度,抢占式调度有很 ...
- python正则表达式的学习记录
match和findall的区别以及有括号和无括号的区别 strvar = "hello\n\nworld" find_re = re.compile("hello[.| ...
- 批量修改Sqlserver中数据库对象的所属架构
执行以下SQL,将执行结果拷贝出来,批量执行既可. SELECT 'ALTER SCHEMA dbo TRANSFER ' + s.Name + '.' + p.Name FROM sys.Proce ...
- Android五:Activity
生命周期: onCreate onStart onResume onPause:在该状态如果有优先级更高的程序,那此进程可能被kill;如果是被重新执行,则回到onResume状态. onStop : ...
- 黄聪:异步加载JS的4种方式(详解)
方案1:$(document).ready <!DOCTYPE html> <html> <head> <script src="http://co ...
- sqlite数据库执行full outer join
sqlite数据库执行full outer join时提示:RIGHT and FULL OUTER JOINs are not currently supported. sqlite数据库不支持(+ ...
- GL_Oracle Erp常用的报表(汇总)
2014-06-27 BaoXinjian 1. 总账系统