Lua学习笔记三之从Lua中调用C

     继续学习Lua与C交互,下面是在学习Lua中调用C定义函数的笔记以及自己的理解,其中学习过程中的写的测试代码可以从我的GitHub下载。

     0、对于能被Lua调用的C函数,必须注册这个C函数,以便用某种适当的方式将函数地址告诉Lua。当Lua调用C函数时,使用了与C调用Lua函数时相同的栈。C函数从栈中获取函数参数,并将结果压入栈中。为了在栈中将函数结果与其他值区分,C函数还应该返回其压入栈中的结果数量。 栈不是一个全局性的结果,这是一个重要的概念。每个函数都有自己的局部私有栈。当Lua调用一个C函数时,第一个参数总是这个局部栈的索引1。即使这个C函数又调用了Lua代码,并且Lua代码又调用了相同的C函数,这些C函数调用只看到自己的私有栈,它们第一个参数的索引都是1。

     1、所有注册到Lua中的函数都具有相同的原型,该原型就是定义在lua.h中的lua_CFunction:typedef int (*lua_CFunction) (lua_State *L)。从C语言观点来看,这个C函数只有一个参数,即Lua的状态。它返回一个整数,表示其压入栈中的返回值数量, 因此这个函数无须在压入结果前清空栈。在它返回后,Lua会自动删除栈中结果之下的内容。

     2、在C的应用程序(或Lua解释器)中,可以使用lua_pushcfunction和lua_setglobal两个函数来完成注册函数,使得这个用C实现的函数,被Lua调用。lua_pushcfunction函数要求传入一个指向C函数的指针,它会在Lua中创建一个“函数”类型的值,该值就表示这个C函数。 当注册完后,这个C函数就具有了与其他Lua函数一样的行为。Lua通过这个记录过程记录下C函数,然后使用这些函数的地址直接调用它。也就是说,Lua调用C函数时,并不依赖于函数名、包的位置或可见性规则,而只依赖于注册时被传入的函数地址。

     3、当用C函数扩展Lua时,最好将代码设计为一个C模块,主要是方便后面扩展。辅助库位这项工作提供了一个函数luaL_register,这个函数接收一些C函数及其名称,并将这些函数注册到一个与模块同名的table中。通常,C模块中只有一个公共(外部)函数,用于创建C模块,而其他所有的函数都是私有的,在C语言中声明为static。当luaL_register以NULL作为库名调用时,luaL_register不会创建任何用于存储函数的table,而是以栈顶的table的存储函数的table。

     4、 当一个C函数从Lua收到一个字符串参数时,必须遵循两条规则:不要在访问字符串时从栈中弹出它;不要修改字符串。 当一个C函数需要创建一个字符串返回给lua时,C代码必须处理字符串缓存的分配和释放、缓存溢出等问题。Lua API也提供了一些函数来帮助完成这些任务。我们在使用这些API时可参照Lua字符串库lstrlib.c的实现。这些会把字符串压入栈中的API,一旦把字符串压入栈中,则栈中的字符串就由Lua来管理了,也就是说,从C中向栈中压入字符串,通常在API中都会有分配新的内存以及复制字符串的操作。

     5、通常,C函数需要保存一些非局部的数据,这些数据的生命时间比C函数的指向更久。C API提供了3中地方来保存这类数据:注册表、环境和upvalue,这类似于一个Lua函数,存放其非局部的数据,分别是全局变量、函数环境和非局部的变量(closure中)。注册表是一个全局的table(应该是对当前lua虚拟机是全局的),它只能被C代码访问。通常,可以用它来保存那种需要在几个模块中共享的数据。如果需要保存一个模块的私有数据,那么应该使用环境。与Lua函数一样,每个C函数都有自己的环境table。通常,一个模块内的所有函数共享一个环境table,由此它们可以共享数据。最后,C函数也可以拥有upvalue,upvalue是一种与特定函数相关联的Lua值。这三种方式(注册表、环境和upvalue)都使用了伪索引。

     6、注册表总是位于一个伪索引(Pseudo-Index)上,这个索引值由LUA_REGISTRYINDEX定义。 伪索引就像一个栈中的索引,但它所关联的值不在栈中。 Lua API中的大多数函数都能接受伪索引,但像lua_remove和lua_insert这种操作栈本身的函数却只能使用普遍索引。注册表是一个普通的Lua table,可以用任何Lua的值(除了nil)来索引它。当需要在一个C变量中保存一个指向Lua值得引用时,就要用到“应用系统”,即int r = LuaL_ref(L,LUA_REGISTRYINDEX)。这样就将相应的Lua值(比如table,函数等值)与r关联起来了,下次使用这些Lua值,只需调用lua_rawgeti(L,LUA_REGISTRYINDEX,r)即可,相应的值就会压入栈顶。最后,释放该值和引用,就可以这样写:luaL_unref(L,LUA_REGISTRYINDEX,r)。

     7、upvalue机制实现了一种类似于C语言中静态变量的机制,这种变量只在一个特定的函数可见。在调用这个函数时,就可以通过伪索引来访问这些upvalue。
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值