Lua不仅可以是一个独立运行的程序包,也可以是一个用来嵌入到其他应用程序库。Lua解释器是一个使用lua标准库实现的独立的解释器,是一个很小的应用。解释器负责程序和使用者的接口:从使用者哪里获取文件或者字符串,并传给lua标准库,lua标准库负责最终的代码运行。
C和lua的两种交互方式:
1、C作为应用程序语言,lua作为一个库使用;
2、Lua作为应用程序语言,C作为库使用。
这两种方式,C语言都使用相同的API与lua通信,因此C和lua交互部分的接口成为C API。C API是一个C代码与lua进行交互的函数集。包括以下组成部分:读写lua全局变量的函数,调用lua函数的函数,运行lua代码批那段的函数,注册C函数然后可以在lua中被调用的函数。
使用C编程时,C和lua之间通信的关键在于一个虚拟的栈,几乎所有的API调用都是对栈上的值进行操作,所有的C与lua之间的数据交换也都是通过这个栈来完成。下面我们先介绍lua常用的一些函数,再介绍栈操作函数。
一、lua基础库函数
在上一次的学习中已经搭建了lua运行环境,因此现在仅介绍函数用法用途。
lua_open() : 创建一个新的lua环境函数,相当于lua库(模块启动)
open返回lua结构体指针(lua_State),指向这个结构体的指针作为所有lua函数的第一个参数。
lua_pcall() : 读取/写入lua环境的全局变量函数,注册可以被lua调用的新函数的函数;
以下函数加载lua各辅助库:
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
在5.0之后的版本,上面的几个函数用下面函数替代即可,使用更简单了:
luaL_openlibs(L);
Lua_close();
二、堆栈操作函数
1、压栈函数
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); /* 字符串(指定长度,忽略\0) */
void lua_pushstring (lua_State *L, const char *s); /* 字符串,\0则结束*/
2、判断堆栈中的值类型
int lua_isnil(lua_State *L, int index);
int lua_isboolean(lua_State *L, int index);
int lua_isnumber(lua_State *L, int index);
int lua_isstring(lua_State *L, int index);
lua_isnumber和lus_isstring函数不检查这个值是否是制定的类型,而是看它是否能被转换成制定的那个类型。任何数字类型都满足lua_isstring。
Lua.h定义的类型:
LUA_TNIL
LUA_TBOOLEAN
LUA_TNUMBER
LUA_TSTRING
LUA_TTABLE
LUA_TFUNCTION
LUA_TUSERDATA
LUA_TTHREAD
堆栈索引:
栈中第一个入栈的元素索引为1,第二个入栈的元素索引为2,以此类推,即从栈底数起1、2、3、...。同时,索引可以为负数,即从栈顶起,-1、-2、-3、...。
3、其他堆栈操作
int lua_gettop (lua_State *L);
返回堆栈中元素个数,也既是栈顶元素的索引。
void lua_settop (lua_State *L, int index);
设置栈顶位置。如果开始的栈顶高于新的栈顶,顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的空值( nil)到栈上。特别的,lua_settop(L,0)清空堆栈。
void lua_pushvalue (lua_State *L, int index);
拷贝索引指定的值到栈顶。(不论指定索引中的值的类型是什么)
void lua_remove (lua_State *L, int index);
lua_remove 移除指定索引位置的元素,并将其上面所有的元素下移来填补这个位置的空白。
void lua_insert (lua_State *L, int index);
lua_insert 移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空
隔。
void lua_replace (lua_State *L, int index);
lua_replace 从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操
作。
三、例子
下面的两个函数可以很好的理解栈的操作和过程,例子本身比较简单,分析一下代码就能理解。
static void stackdump(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: /* type string */
{
printf("%s", lua_tostring(L, i));
break;
}
case LUA_TBOOLEAN: /* type boolean */
{
printf(lua_toboolean(L, i) ? "true" : "false");
break;
}
case LUA_TNUMBER: /* type number */
{
printf("%g", lua_tonumber(L, i));
break;
}
default: /* type other */
{
printf("%s", lua_typename(L, t));
break;
}
}
printf(" ");
}
printf("\n");
}
void stack_op()
{
lua_State *L = lua_open();
lua_pushboolean(L, 1);
lua_pushnumber(L, 10);
lua_pushnil(L);
lua_pushstring(L, "hello");
/* true 10 nil 'hello' */
stackdump(L);
/* true 10 nil 'hello' true*/
lua_pushvalue(L, -4);
stackdump(L);
/* true 10 true 'hello' */
lua_replace(L, 3);
stackdump(L);
lua_settop(L, 6);
stackdump(L);
lua_remove(L, -3);
stackdump(L);
lua_settop(L, -5);
stackdump(L);
lua_close(L);
//return 0;
}
$ ./lua_test
true 10 nil hello
true 10 nil hello true
true 10 true hello
true 10 true hello nil nil
true 10 true nil nil
true