简介
C API 是一组能使用C代码与Lua交互的函数。其中包括读写Lua全局变量、调Lua函数、运行一段Lua代码,以及注册C函数以供Lua代码调用等。
Lua和C语言之间的数据交换使用了一个抽象的栈。栈中的每个元素都能保存任何类型的Lua值。要获取Lua中的一个值时,只要调用一个Lua API函数,Lua就将指定的值压入栈中。要将一个值传给Lua时,需要现将这个值压入栈,然后调用Lua API,Lua就会获取该值并将其从栈中弹出。
压入元素
对于每种可以呈现在Lua中的C类型,API都有一个对应的压入函数。
void lua_pushnil(lua_State* L); //常量nil
void lua_pushboolean(lua_State* L, int bool); //bool 值
void lua_pushnumber(lua_State* L, lua_Number n); //双精度浮点数
void lua_pushinteger(lua_State* L, lua_Interger); //整数
void lua_pushlstring(lua_State* L, const char* s, size_t len); //任意字符串,及其长度,包含任意二进制数据
void lua_pushnil(lua_State* L, const char* s); //以0结尾的字符串
对于Lua持有的字符串,它都会生成一个内部副本,或者复用现有内容。因此,即使在这些函数返回后立即释放或者修改这些字符串,都不会出问题。
向栈中压入一个元素时,应该确保栈中具有足够的空间。启动Lua时,或者Lua调用C语言时,栈中至少会有20个空闲的槽(lua.h中的LUA_MINSTACK定义的)。一般情况时是够用的。如果有些情况需要更多的栈空间,就要调用lua_checkstack来检查是否有足够的空间
int lua_checkstack(lua_State* L, int sz)
查询元素
栈索引
API使用索引来引用栈中元素。第一个压入栈的元素索引为1,第二个则为2。同时也可以使用复数来作为索引访问栈中元素。-1则表示最后一个压入栈的元素,即栈顶元素,-2表示栈顶下面的一个元素,以此类推。
检查元素类型
为了检查一个元素是否为特定类型,API提供了一系列的函数lua_is*,其中*可以是任意Lua类型。这些函数有 lua_isnumber、lua_isstring、lua_istable等。
实际上,lua_isnumber不会检查值是否为数字类型,而是检查是否能转换为数字类型。lua_isstring也有同样的行为。因此,对任意数字 lua_isstring 都返回真。
查看元素类型
lua_type 会返回赵中元素的类型。每种类型都对应一个常量,这些常量定义在头文件lua.h中。他们是
LUA_TNIL
LUA_TBOOLEAN
LUA_TNUMBER
LUA_TSTRING
LUA_TTABLE
LUA_TTHREAD
LUA_TUSERDATA
LUA_TFUNCTION
另外,若要检查一个元素是否为真正的数字或者字符串(无须转换的),可以使用下列函数:
int lua_toboolean(lua_State* L, int index)
lua_Number lua_tonumber(lua_State* L, int index)
lua_Interger lua_tointerger(lua_State* L, int index)
const char* lua_tokstring(lua_State* L, int index, size_t *len) //len 字符串长度
size_t lua_objlen(lua_State* L, int index)
如果指定的元素具有不正确的类型,调用这些函数也不会有问题。这种情况下, lua_toboolean、lua_tonumber、lua_tointerger、lua_objlen 会返回0,其他函数返回NULL。
lua_tolstring 函数会返回一个只想内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。这个内部副本不能修改。lua保证只要这个对应的字符串的值还在栈中,那么这个指针就是有效的。当Lua调用的一个C函数返回时,Lua就会情况它的栈。所以不要在C函数之外使用C函数内部获得的指向Lua字符串的指针。
lua_objlen函数可以返回一个对象的长度"长度",对于字符串和table这个值是操作符 "#" 的结果。这个函数还可以用于获取一个完全userdata(full userdata)的大小。
下面的方法可以定义栈中的值的类型:
static void stack_dump(lua_State *L) {
int i;
int top = lua_gettop(L);//获取栈顶元素索引
for (i = 1; i <= top; i++) {
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: {
printf("'%s'", lua_tostring(L, i));
break;
}
case LUA_TBOOLEAN: {
printf(lua_toboolean(L, i) ? "true" : "false");
break;
}
case LUA_TNUMBER: {
printf("'%g'", lua_tostring(L, i));
break;
}
default:
printf("%s", lua_typename(L, t));
break;
}
}
}
其他栈操作
除了在C语言和栈之间数据交换函数之外,API还提供了一下用于普通栈操作的函数
int lua_gettop(lua_State* L);
void lua_settop(lua_State* L, int index);
void lua_pushvale(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来补足大小。
API函数还提供了一个宏用于从栈中弹出n个元素
#define lua_pop(L,n) lua_settop(L, -(n) -1)
lua_pushvalue: 函数会将指定索引上的值的副本压入栈。
lua_remove: 删除指定索引上的元素,并将位置之上的所有元素下一填补空缺
lua_insert: 会上移指定位置之上的所有元素一开辟一个槽的空间,然后将栈顶元素移到改位置
lua_replace: 弹出栈顶的值,并将改值设置到指定索引上,当它不会移动任何东西
示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#include "lua.h"
#include "lauxlib.h"
}
#endif // __cplusplus
static void stack_dump(lua_State *L) {
int i;
int top = lua_gettop(L);//鑾峰彇鏍堥《鍏冪礌绱㈠紩
for (i = 1; i <= top; i++) {
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: {
printf("'%s'", lua_tostring(L, i));
break;
}
case LUA_TBOOLEAN: {
printf(lua_toboolean(L, i) ? "true" : "false");
break;
}
case LUA_TNUMBER: {
printf("%g", lua_tonumber(L, i));
break;
}
default:
printf("%s", lua_typename(L, t));
break;
}
printf(" ");
}
printf("\n");
}
int main() {
lua_State* L = luaL_newstate();
lua_pushboolean(L, 1); //1
lua_pushnumber(L, 10);//2
lua_pushnil(L);//3
lua_pushstring(L, "hello world");//4
stack_dump(L);
lua_pushvalue(L, -4); //true 10 nil 'hello world' true 娣诲姞浜嗕竴涓?true
stack_dump(L);
lua_replace(L, 3); // true 10 true 'hello world'
stack_dump(L);
lua_settop(L, 6); //true 10 true 'hello world' nil nil
stack_dump(L);
lua_remove(L, -3); //true 10 true nil nil
stack_dump(L);
lua_settop(L, -5); //true
stack_dump(L);
lua_close(L);
system("pause");
}
网友评论