27 Calling C from Lua
在这里说Lua调用C函数,并不意味着Lua可以调用任意的C函数。与之前C调用Lua函数一样,在这里同样需要遵循一些规则:传递参数,得到结果。不仅如此,Lua要调用C函数,我们首先需要注册这个函数,即需要将该函数的地址传递给Lua。
当Lua调用C函数的时候,也是使用栈来做参数和返回结果的传递。C函数从栈中得到参数,然后将结果push至栈中。
在这里一个重要的概念是:栈不是一个全局结构;每个函数都有它自己的局部栈。当Lua调用C函数的时候,第一个参数总是栈中index为1的那个值。甚至当一个C函数调用了Lua代码,然后Lua再调用一个C函数,每次调用都只可以访问到各自私有的栈,第一个参数都是栈中index为1的那个。
27.1 C Functions
以书上的例子,如何实现一个简单的返回一个给定数的sin值的函数:
e.g. static int l_sin (lua_State *L) { double d = lua_tonumber(L,1); /* 得到一个参数 */ lua_pushnumber(L,sin(d)); /* 将结果push 进去 */ return 1; /* 返回结果的数量*/ }任何注册到Lua的函数都有一个同样的原型,在头文件lua.h 中定义为lua_CFuntion :
typedef int (*lua_CFuntion) (lua_State *L)从C的角度来看,一个C函数以一个Lua state作为其唯一参数,然后返回一个代表函数返回值数量的整型数。从这点来看,函数不需要在push结果之前将栈清空,在函数返回之后,Lua会自动存储其结果然后将整个栈清空。
e.g. lua_pushcfunction(L,l_sin); lua_setglobal(L,"mysin"); /* 在lua中创建一个全局变量mysin ,然后将c函数赋值给mysin*/在这之后,就可以在Lua中使用mysin这个函数了。
e.g. static int l_sin(lua_State *L) { double d = luaL_checknumber(L,1) /* 检查参数 */ lua_pushnumber(L,sin(d)); return 1; }如果传递的参数为非数值类型,此时将会得到错误信息:
e.g. co = coroutine.wrap(function ( a ) return pcall(function ( x ) coroutine.yield(x[1]) return x[3] end,a) end) print(co({10,3,-8,15}))这个例子我在sublime中执行没有问题,书本上是说这个有问题的,需要再注意。书上对这个例子的解释是:pcall是一个c函数,因此Lua不能延迟这个函数的执行,因为在ANSI C中没有方法延迟一个C函数的执行然后在某个时间点再恢复这个函数。
e.g. static int l_dir(lua_State *L) { /*code*/ }下一步是需要声明一个数据结构以各自函数的名字存储需要加入到这个库中的所有函数,该数据结构的类型为:luaL_Reg,数组的数据结构有两个字段:一个字符串代表函数的名字,一个函数指针
e.g. static const struct luaL_Reg mylib[] = { {"dir",l_dir), {NULL,NULL} };以{NULL,NULL}结尾是必须的,用来作为结尾符号。最后声明一个主函数,使用luaL_newlib:
e.g. int luaopen_mylib(lua_State *L) { luaL_newlib(L,mylib); return 1; }创建完之后,便是将库链接到编译器了。最方便的方式便是采用动态链接的特性(windows中创建mylib.dll,linux中创建mylib.so )然后加入到C路径中去。经过这些步骤,便可以从Lua中加载这个库了,使用require实现:
e.g. local mylib = require "mylib"以上这步将动态链接库mylib链接到了lua中,找到luaopen_mylib函数,以一个C函数注册该函数然后调用该函数以打开模块。
《Programming in Lua 3》读书笔记(二十三)
原文地址:http://blog.csdn.net/zh379835552/article/details/38824843