24.2.3 其他堆栈操作 |
除开上面所提及的C与堆栈交换值的函数外,API也提供了下列函数来完成通常的堆栈维护工作:
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返回堆栈中的元素个数,它也是栈顶元素的索引。注意一个负数索引-x对应于正数索引gettop-x+1。lua_settop设置栈顶(也就是堆栈中的元素个数)为一个指定的值。如果开始的栈顶高于新的栈顶,顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的空值(nil)到栈上。特别的,lua_settop(L,0)清空堆栈。你也可以用负数索引作为调用lua_settop的参数;那将会设置栈顶到指定的索引。利用这种技巧,API提供了下面这个宏,它从堆栈中弹出n个元素:
#define lua_pop(L,n) lua_settop(L, -(n)-1)
函数lua_pushvalue压入堆栈上指定索引的一个抟贝到栈顶;lua_remove移除指定索引位置的元素,并将其上面所有的元素下移来填补这个位置的空白;lua_insert移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空隔;最后,lua_replace从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作。注意到下面的操作对堆栈没有任何影响:
lua_settop(L, -1); /* set top to its current value */
lua_insert(L, -1); /* move top element to the top */
为了说明这些函数的用法,这里有一个有用的帮助函数,它dump整个堆栈的内容:
static void stackDump (lua_State *L) {
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: /* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */
printf("%g", lua_tonumber(L, i));
break;
default: /* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
这个函数从栈底到栈顶遍历了整个堆栈,依照每个元素自己的类型打印出其值。它用引号输出字符串;以%g的格式输出数字;对于其它值(table,函数,等等)它仅仅输出它们的类型(lua_typename转换一个类型码到类型名)。
下面的函数利用stackDump更进一步的说明了API堆栈的操作。
#include <stdio.h>
#include <lua.h>
static void stackDump (lua_State *L) {
...
}
int main (void) {
lua_State *L = lua_open();
lua_pushboolean(L, 1); lua_pushnumber(L, 10);
lua_pushnil(L); lua_pushstring(L, "hello");
stackDump(L);
/* true 10 nil `hello' */
lua_pushvalue(L, -4); stackDump(L);
/* true 10 nil `hello' true */
lua_replace(L, 3); stackDump(L);
/* true 10 true `hello' */
lua_settop(L, 6); stackDump(L);
/* true 10 true `hello' nil nil */
lua_remove(L, -3); stackDump(L);
/* true 10 true nil nil */
lua_settop(L, -5); stackDump(L);
/* true */
lua_close(L);
return 0;
}