Lua与C是通过栈进行交换数据的,这个栈与我们在数据结构中所说的栈类似,遵循LIFO规则。下面是从官方文档上截取的关于栈操作的 C API,对其进行分类整理了。
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_pushinteger (lua_State *L, lua_Integer n); void lua_pushstring (lua_State *L, const char *s); const char *lua_pushfstring (lua_State *L, const char *fmt, ...); void lua_pushlstring (lua_State *L, const char *s, size_t len); const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp); void lua_pushcfunction (lua_State *L, lua_CFunction f); int lua_pushthread (lua_State *L); void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); void lua_pushlightuserdata (lua_State *L, void *p);
2. 获取栈中元素:
在栈中第一个元素的索引为1, 下一个元素为2, 依次类推。我们也可以用栈顶作为参照来存取元素,利用负索引,在这种情况下,-1表示栈顶元素的索引,-2表示倒数第二个元素。
lua提供了如下函数来判断元素类型: lua_is*
int lua_is*(lua_State *L, int index); int lua_type (lua_State *L, int index);
The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA.
为了从栈中获取值,使用lua_to...函数:
int lua_toboolean (lua_State *L, int index); lua_Integer lua_tointeger (lua_State *L, int index); lua_Number lua_tonumber (lua_State *L, int index); const char *lua_tostring (lua_State *L, int index); const char *lua_tolstring (lua_State *L, int index, size_t *len); lua_State *lua_tothread (lua_State *L, int index); void *lua_touserdata (lua_State *L, int index);
lua为了方便检查元素类型并获取元素的值,提供了luaL_check*函数,以及luaL_opt*函数。如果不满足对应的类型,则 throw an error。
int luaL_checkint (lua_State *L, int narg); Checks whether the function argument narg is a number and returns this number cast to an int.
lua_Number luaL_checknumber (lua_State *L, int narg); Checks whether the function argument narg is a number and returns this number.
const char *luaL_checklstring (lua_State *L, int narg, size_t *l); Checks whether the function argument narg is a string and returns this string; if l is not NULL fills *l with the string‘s length.
void *luaL_checkudata (lua_State *L, int narg, const char *tname); Checks whether the function argument narg is a userdata of the type tname
int luaL_optint (lua_State *L, int narg, int d); If the function argument narg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. Otherwise, raises an error.
const char *luaL_optlstring (lua_State *L, int narg, const char *d, size_t *l); If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error. If l is not NULL, fills the position *l with the results‘s length.
const char *luaL_optstring (lua_State *L, int narg, const char *d); If the function argument narg is a string, returns this string. If this argument is absent or is nil, returns d. Otherwise, raises an error.
3. 其他的栈操作:
int lua_gettop (lua_State *L); Returns the index of the top element in the stack. Because indices start at 1, this result is equal to the number of elements in the stack (and so 0 means an empty stack).
void lua_settop (lua_State *L, int index); Accepts any acceptable index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. If index is 0, then all stack elements are removed.
void lua_pushvalue (lua_State *L, int index); Pushes a copy of the element at the given valid index onto the stack.
void lua_remove (lua_State *L, int index); Removes the element at the given valid index, shifting down the elements above this index to fill the gap. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.
void lua_insert (lua_State *L, int index); Moves the top element into the given valid index, shifting up the elements above this index to open space. Cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position.
void lua_replace (lua_State *L, int index); Moves the top element into the given position (and pops it), without shifting any element (therefore replacing the value at the given position).
void lua_pop (lua_State *L, int n); Pops n elements from the stack.
4. C API错误处理:
当我们向Lua添加C函数时,如果C函数中发生错误,可以使用luaL_error函数,它会清理所有在Lua中需要被清理的,然后和错误信息一起回到最初的执行lua_pcall的地方。
int luaL_error (lua_State *L, const char *fmt, ...); Raises an error. The error message format is given by fmt plus any extra arguments, following the same rules of lua_pushfstring. It also adds at the beginning of the message the file name and the line number where the error occurred, if this information is available. This function never returns, but it is an idiom to use it in C functions as return luaL_error(args).
5. Table的操作:
1) 在栈上创建一个新的table
void lua_createtable (lua_State *L, int narr, int nrec); Creates a new empty table and pushes it onto the stack. The new table has space pre-allocated for narr array elements and nrec non-array elements. This pre-allocation is useful when you know exactly how many elements the table will have. Otherwise you can use the function lua_newtable. void lua_newtable (lua_State *L); Creates a new empty table and pushes it onto the stack. It is equivalent to lua_createtable(L, 0, 0).
2) 读取Lua代码中已有的table:
对于已经存在于lua _G table中的成员,可以用如下方法获取:
void lua_getglobal (lua_State *L, const char *name); Pushes onto the stack the value of the global name. It is defined as a macro: #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
此函数返回后,对应的成员位于栈顶处。
3) 读取table中键为key的元素
void lua_getfield (lua_State *L, int index, const char *k); Pushes onto the stack the value t[k], where t is the value at the given valid index. As in Lua, this function may trigger a metamethod for the "index" event
4) 设置table中键为key的元素值
void lua_setfield (lua_State *L, int index, const char *k); Does the equivalent to t[k] = v, where t is the value at the given valid index and v is the value at the top of the stack. This function pops the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event
调用这个方法前,需要先将value压入栈顶。lua_push*
5) 读取数组中索引为key的元素:
void lua_rawgeti (lua_State *L, int index, int n); Pushes onto the stack the value t[n], where t is the value at the given valid index. The access is raw; that is, it does not invoke metamethods.
6) 设置数组中索引为key的元素值:
void lua_rawseti (lua_State *L, int index, int n); Does the equivalent of t[n] = v, where t is the value at the given valid index and v is the value at the top of the stack. This function pops the value from the stack. The assignment is raw; that is, it does not invoke metamethods.
调用这个方法前,也是需要先将value压入栈顶,lua_push*
7) 获取table中元素的个数:
size_t lua_objlen (lua_State *L, int index); Returns the "length" of the value at the given acceptable index: for strings, this is the string length; for tables, this is the result of the length operator (‘#‘); for userdata, this is the size of the block of memory allocated for the userdata; for other values, it is 0.
6. 查看栈
在<programing in lua>一书中,提供了stack_dump函数,用于查看当前的栈中所有元素,现将其源码贴出:
void stack_dump(lua_State *L) { int i; int top = lua_gettop(L); printf("Stack has %d elements:\n\t", top); for(i = 1; i <= top; ++i){ int type = lua_type(L, i); switch(type){ 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, i)); break; } printf("\t"); } printf("\n"); }
6. lua-epoll的简单分析:
我刚开始学习的时候,看了上面这么多API,感觉还不怎么熟练,所以就找了一个简单的开源代码来学习。
源码地址: https://github.com/Hevienz/lua-epoll
README.md文件中有说明如何使用该模块,具体的分析见下一篇文章。