c中获取lua的函数(不js回调函数 参数传递),只为在c中将lua的函数传递下去

Windows10用户联盟QQ群:
函数是一组一起执行任务的语句。可以把代码放到独立的函数中。怎么划分代码功能之间的不同,但在逻辑上划分通常是让每个函数执行特定的任务。
Lua语言提供了程序可以调用大量的内置方法。例如,方法print()打印作为输入传参数在控制台中。
函数是已知的各种名称,如方法或子程序或程序等。
定义一个函数
在Lua编程语言中的方法的定义一般形式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
在 Lua 编程语言的方法定义包括方法头和方法体。这里是方法的所有部件
可选函数适用范围:可以使用关键字本地范围的限制功能或忽略的范围部分,这将使它成为一个全局函数。
函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数:一个参数是像占位符。当调用一个函数,将值传递给参数。这个值被称为实际参数或参数。参数列表是指类型,顺序和数量的方法的参数。参数是可选的;也就是说,方法可能没有参数。
函数体:方法主体包含了定义方法做什么的语句的集合。
返回:在Lua中可以通过下面的逗号分隔的返回值,return关键字返回多个值。
下面是一个函数的源代码调用max()。这个函数有两个参数num1与num2并返回两者之间的最大值:
--[[ function returning the max between two numbers --]]
function max(num1, num2)
if (num1 & num2) then
result = num1;
result = num2;
函数参数:
如果一个函数使用参数,它必须声明接受的参数值变量。这些变量被函数的形式参数调用。
正式的参数表现得就像在函数内部其他本地变量和在进入函数创建并在退出时销毁。
调用函数:
当创建一个Lua函数,给什么样的功能,必须做一个定义。要使用一个方法,将不得不调用该函数来执行定义的任务。
当程序调用一个函数,程序的控制转移到被调用的函数。被调用函数进行定义的任务和在执行它的return语句或当其功能的终端到达时,程序控制返回到主程序。
而调用只是需要传递所需的参数以及方法名的方法,如果方法返回一个值,那么你可以存储返回的值。例如:
function max(num1, num2)
if (num1 & num2) then
result = num1;
result = num2;
-- calling a function
print(&The maximum of the two numbers is &,max(10,4))
print(&The maximum of the two numbers is &,max(5,6))
当我们运行上面的代码中,将得到下面的输出。
The maximum of the two numbers is
The maximum of the two numbers is
分配和传递函数
在Lua中,我们可以指定函数的变量,也可以将它们作为另一个函数的参数。下面是一个简单的例子,用来分配Lua传递一个函数作为参数。
myprint = function(param)
print(&This is my print function -
##&,param,&##&)
function add(num1,num2,functionPrint)
result = num1 + num2
functionPrint(result)
myprint(10)
add(2,5,myprint)
当我们运行上面的代码中,将得到下面的输出。
This is my print function -
This is my print function -
函数与变量参数
可以在Lua中创建一个具有可变参数的函数......作为它的参数。我们可以通过看一个例子,利用可变参数该函数将返回平均值。
function average(...)
result = 0
local arg={...}
for i,v in ipairs(arg) do
result = result + v
return result/#arg
print(&The average is&,average(10,5,3,4,5,6))
当我们运行上面的代码中,将得到下面的输出。
The average is 5.5
标签:&&&&&&&&&&&&Lua和C语言的交互_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Lua和C语言的交互
上传于||文档简介
&&L​u​a​和​C​语​言​的​交​互
阅读已结束,如果下载本文需要使用2下载券
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩16页未读,继续阅读
你可能喜欢二次元同好交流新大陆
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
1&Proto,函数原型。定义:lua编译器生成的对象。其中包含一系列lua指令,常量表,等等,是一个可执行对象的原型。2 LClosure,lua闭包。定义:包含了一个Proto及其upvalue的对象,是一个可执行对象。3 CClosure,c api。定义:包含了一个c api及其upvalue的对象,是一个可执行对象。 这里我们同时研究LClosure和CClosure的调用机制,LClosure和CClosure统称Closure。 首先,了解一些基础结构。1 lua栈,stack。定义:lua_State.stack数组。 用途:1 和c api交互
2 virtual machine寄存器
3 存储Proto的局部变量综合来说stack和CallInfo一起构成调用栈帧,每个调用栈帧包含一个CallInfo结构以及stack的一段。CallInfo和stack都只增不减,避免频繁分配内存。 stack的一个元素是一个TValue。TValue是值传递语义。其他一些结构用StkId来保存TValue指针。stack可动态增长,一旦stack有变,其他保存StkId的地方会失效,这时需要重新设置这些StkId(例如所有CallInfo)2 CallInfo,调用栈帧。 func,Closure在stack中的位置。 top,本帧的最大栈位置,对于LClosure,这个位置是编译器生成的,就是Proto.maxstacksize。对于CClosure,默认给出LUA_MINSTACK的空间,可用lua_checkstack函数来扩展。 l.base,当前栈帧基址,所有寄存器操作都是基于该位置的。 l.savedpc,指令指针。 stack与c交互的部分就是从func之后的第一个位置开始计算的(见lua_settop) Closure的调用分为从c代码调用(入口是luaD_call)和从lua代码调用(入口是OP_CALL指令)两个入口(暂不考虑coroutine)。进一步阅读发现,函数调用的细节主要由luaD_precall,luaV_execute(仅对LClosure),luaD_poscall三个函数实现。 luaD_precall负责建立调用栈帧等操作,luaD_poscall负责回退栈帧等操作。 luaV_execute赋值执行lua目标码。luaV_execute中一旦有改变stack的代码,所有涉及到的StkId都会重新获取,相关代码比较杂,比如Protect,重设ci-&u.l.base,重设ra等等。 我们分几种情况分析。 1&c代码调用CClosure。 调用lua_call时,stack上,func后面紧跟参数,执行到luaD_precall,构造新的CallInfo并设置CallInfo.func=func,直接调用CClosure。CClosure内部,栈底就是第一参数(前文已诉,交互栈从func之后的第一个位置开始计算),lua_call和CClosure之间满足调用约定。 2 c代码调用LClosure。 luaD_precall相关代码 base=func+1;(固定参数) 或&base = adjust_varargs(L, p, n);(可变参数) ci-&u.l.base =结合luaV_execute相关代码 base = ci-&u.l.
#define RA(i) (base+GETARG_A(i))adjust_varargs将调用者压入的固定参数部分往后移动形成如下格局func + fixargs + varargs &----& func + nils + varargs + fixargsl.base指向第一个fixarg。编译器并不为varargs保留寄存器,而是当有引用时再把varargs一起拷贝到当前栈顶。总之无论是否可变参数,寄存器都从l.base开始定义,l.base指向第一个固定参数。第一个固定参数肯定是寄存器0。 从lua_call的角度看,移动参数的过程是透明的,func+1这个位置是第一个参数。编译器生成指令时,遇到参数的名字,生成代码应该对应寄存器编号。要了解编译器的这部分代码,我们先来看看编译器处理局部变量的机制。 结构expdesc是编译器生成代码的中间转换结构。parser一边遍历源码一边生成目标码,但遍历的同时目标码经常还无法生成,需要延迟生成,这时就只能先生成一个expdesc,传递给后面的函数进行进一步处理。其实这就是编译原理中所说的综合属性和继承属性。只不过lua更复杂一点的是由于是一次遍历,还涉及重新修改目标码的操作。 函数luaK_storevar根据变量和值的信息(两个expdesc)生成相关代码。 函数searchvar根据名字返回寄存器id。 我们看其内部发现,Proto.locvars保存的是变量名等信息,用于调试和编译期使用,与寄存器无关。 而编译期数据Dyndata.actvar里的值保存的是Proto.locvars的下标,也不是寄存器id。Dyndata.actvar数组本身的下标才和寄存器id相关。(见getlocvar。貌似作者注释actvar.arr.idx有误,代码明明表示这是Proto.locvars下标,并不是寄存器id) 函数new_localvar和adjustlocalvars一起填充Proto.localvars和Dyndata.actvar两个结构以及FuncState.nactvar。 函数luaK_reserveregs预留若干寄存器。 寄存器是栈式线性分配,FuncState.freereg标识第一个空闲的寄存器id。 有了这些准备,我们来看编译器的funcstat函数里面的body函数。open_func里有fs-&freereg = 0;fs-&nactvar = 0;说明函数开始时,寄存器是从0开始分配的。 看函数parlist。里面用new_localvar和adjustlocalvars定义所有参数。最后调用luaK_reserveregs预留参数数量的寄存器,前面说了,寄存器开始为0,这表明参数是从寄存器0开始预留的。 预留了寄存器,那么什么时候使用呢,答案是对参数进行索引的时候。比如我们对参数赋值,p1=1,生成代码就要索引参数对应的寄存器。当编译器读到参数时,会调用singlevar,singlevar会调用searchvar最后生成一个VLOCAL类型的expdesc。该expdesc保存的就是寄存器id。(更进一步,如果是上述赋值操作,那么编译器再调用assignment,assignment会调用luaK_storevar生成代码.) 可见,编译器生成的代码满足调用约定。 3,4 lua代码调用CClosure/LClosure 函数luaK_exp2nextreg用于为一个expdesc分配新的寄存器并生成相应代码。 我们看到了c api和Proto都遵守调用约定。那么OP_CALL呢。从代码看OP_CALL的操作数ra代表Closure,Closure的参数是从寄存器ra+1开始一共有rb-1个。我们看编译期生成OP_CALL的过程。 假设调用一个局部函数,suffixedexp调用primaryexp生成一个VLOCAL的expdesc(包含Closure所在寄存器) 然后调用luaK_exp2nextreg为该Closure新分配一个寄存器并生成相应代码。(比如生成OP_MOVE指令将Closure读到新的位置)。分配新寄存器是必要的,新寄存器就是当前id最大的寄存器,后面才有空闲寄存器来存储参数。 然后调用funcargs。此时传递给funcargs的expdesc是VNONRELOC类型表示Closure的寄存器。funcargs调用luaK_exp2nextreg将参数排列在Closure之后,最后调用luaK_codeABC生成OP_CALL指令。可见OP_CALL指令满足调用约定。
阅读(2673)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'lua函数调用机制',
blogAbstract:'\t函数一词太过模糊。我们使用更精确的词汇来描述。1&Proto,函数原型。定义:lua编译器生成的对象。其中包含一系列lua指令,常量表,等等,是一个可执行对象的原型。2 LClosure,lua闭包。定义:包含了一个Proto及其upvalue的对象,是一个可执行对象。3 CClosure,c api。定义:包含了一个c api及其upvalue的对象,是一个可执行对象。\t这里我们同时研究LClosure和CClosure的调用机制,LClosure和CClosure统称Closure。',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:3,
publishTime:9,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 c 回调 lua 的文章

 

随机推荐