C++与Lua交互的C API

1、C API的介绍

Lua是一种嵌入式的语言。即Lua不是一个单独运行的程序,而是一个可以链接到其他程序的库。通过C API就可以将Lua的功能合并入这些程序。与此同时,一个使用了Lua的程序可以在Lua环境中注册用C语言实现的新函数,由此,就可以向Lua中添加某些无法直接用Lua编写的功能。

由于Lua和C++的数据结构和内存机制不一样,所以在交互的时候需要用到C API提供的一个虚拟栈,所有的操作其实全是对这个虚拟栈的操作,这个堆栈是先进后出的,栈底的索引为1,依次向上加。也可以用负数来表示,栈顶的索引为-1,依次往下减。所有的数据交换,无论是Lua到C语言或C语言到Lua都通过这个栈来完成,这个栈还可以保存中间结果。

C API是一组能使C代码和Lua交互的函数。其中包括读写Lua全局变量,调用Lua函数,运行一段Lua代码,以及注册C函数以供Lua调用。里面提供了一些头文件,如lua.h lauxlib.h lualib.h等。

lua.h定义了Lua提供的基础函数,包括创建lua环境,调用lua函数,读写lua中的全局变量,以及注册供Lua调用的新函数等。这里面的函数前缀都是lua_。

lauxlib.h是一个辅助库,定义了辅助库的辅助函数,这里面的函数都是以luaL_开头的。辅助库是一个使用lua.h中API编写出的一个较高的抽象层。lua的所有标准库编写都用到了辅助库,辅助库主要用来解决实际问题。

lualib.h定义了打开标准库的函数。由于luaL_newstate函数用于创建一个新环境。这个新创建的环境中没有包含预定义的函数,甚至没有print。为了使lua保持小巧,所有的标准库都被组织到了不同的包中。在头文件lualib.h中定义了打开这些库的函数,而辅助库函数luaL_openlibs则可以打开所有的标准库。


2、lua.h函数介绍

这里面有大量的push函数用于将C数据压入虚拟栈中,如下:

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);
lua中的字符串不是以0结尾的,因此它们必须包含一个显式的长度。将字符串压入栈的基本函数是lua_pushlstring,它要求传入一个显式的长度参数,对于0结尾的字符串,可以使用函数lua_pushstring,这个函数可以通过strlen来计算字符串的长度。另外,Lua不会持有指向外部字符串的指针。对于所有Lua持有的字符串,它都会生成一个内部副本,或者复用现有的内容。

另外在向栈中压入一个元素时,应该确保栈中具有足够的空间。当Lua启动时,或者Lua调用C语言时,栈中至少会有20个空闲的位置。如果想要查看栈中是否有足够的空间,可以调用:

int lua_checkstack (lua_State *L, int sz);

前面我们说过,这个栈是根据索引来查找元素的。第一个压入栈的索引为1,第二个为2,一直到栈顶。负数的话,-1代表栈顶,-2代表栈顶下面的元素,一直到栈底。为了检查一个元素是否为特定的类型,API提供了一系列的函数lua_is*,这里的*可以是任意Lua类型。例如:lua_isnumber、lua_isstring、lus_istable等。类似这样的函数的原型为:

int lua_is... (lua_State *L, int index);

实际上,lua_isnumber并不会去检查值是否为数字类型和,而是检查值是否能转换为数字类型。还有一个函数lua_type,它会返回栈中数据的类型。每种类型都有一个常亮表示,这些常量也都定义在lua.h中:

LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD

从栈中取值的话一般是用lua_to*类似的函数:

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);
size_t        lua_strlen (lua_State *L, int index);

如果说,咱们指定的元素转换失败的话,这些函数不会抛出错误,而是lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen会返回0,其他一律返回NULL。另外要注意,lua_tolstring函数会返回一个指向内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。lua_objlen这个函数可以返回一个对象的“长度”。对于字符串和table,这个值是长度操作符“#”的结果。

其他的一些函数也做一下总结:

int  lua_gettop (lua_State *L);
void lua_settop (lua_State *L, int index);
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);

lua_gettop返回栈中元素的个数,其实也就是返回栈顶的索引。lua_settop将栈顶设置为一个指定的位置,也就是修改栈顶元素的数量,还是老套路,新的数量大于以前的,多出来的为nil,新的数量少于以前的,那些就被抛弃了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值