lua與c之間交互是通過“lua堆棧”通信的。不管是lua調用c還是c調用lua,都是通過操作lua堆棧實現的。顧名思義,lua堆棧也滿足后進先出的特點,入棧/出棧都圍繞棧頂進行的。與通用的棧不同的是,這個虛擬棧每個位置都對應一個索引,可以通過索引操作指定位置的數據。1代表棧底,向棧頂依次遞增;-1代表棧頂,向棧底依次遞減,如圖。
1. lua中類型在c中如何表示
要實現c和lua之間的交互,先了解下lua中基本類型與c中類型怎么對應的。lua中有八種基本類型:nil、boolean、number、string、table、function、userdata、thread,其中,userdata分輕量用戶數據(lightuserdata)和完成用戶數據(userdata)兩種。這些類型都可以壓入棧中,在c中統一用TValue結構表示,是一個{值,類型}結構。
(圖片來自http://www.cnblogs.com/sevenyuan/p/4511808.html)
TValue->tt表示類型,類型定義在lua.h,nil為LUA_TNIL,boolean為LUA_TBOOLEAN等
// lua.h #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8
TValue->Value是個union:
int b:只存boolean類型,注:number類型並不存在這里,b只存boolean
lua_Number n:存放所有number類型
void *p:存放輕量用戶數據類型(lightuserdata)
gcObject *gc:存放所有需要垃圾回收的類型,是一個指向union GCObject的指針,通過GCObject可以看到其包含string、userdata、closure、table、proto、upvalue、thread
由此可知,nil、boolean、number、lightuserdata類型是把數據本身直接存在棧里,和lua的垃圾回收無關;而GCObject表示的類型是把數據的內存地址(即指針)存在棧里的,當生命周期結束需要垃圾回收釋放內存。
2. 對堆棧的基本操作
luaL_newstate:創建一個狀態機,
lua_close:關閉狀態機
#include <stdio.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> int main(int argc, char *argv[]){ lua_State *L = luaL_newstate(); //創建一個狀態機 lua_pushnil(L); //nil int type = lua_type(L, -1); printf("nil type = %d\n", type); if(lua_isnil(L, -1)){ printf("------nil-----\n"); } lua_pushboolean(L, 0); //boolean type = lua_type(L, -1); printf("boolean type = %d\n", type); if(lua_isboolean(L, -1)) printf("--------boolean------\n"); lua_pushlightuserdata(L, NULL); //lightuserdata type = lua_type(L, -1); printf("lightuserdata type = %d\n", type); if(lua_islightuserdata(L, -1)) printf("--------lightuserdata------\n"); lua_pushnumber(L, 10); //number type = lua_type(L, -1); printf("number type = %d\n", type); if(lua_isnumber(L, -1)) printf("--------number------\n"); lua_pushstring(L, "string"); //string type = lua_type(L, -1); printf("string type = %d\n", type); if(lua_isstring(L, -1)) printf("--------string------\n"); lua_newtable(L); //table, 創建空表,並壓入棧 type = lua_type(L, -1); printf("table type = %d\n", type); if(lua_istable(L, -1)) printf("--------table------\n"); lua_newuserdata(L, 1024); //userdata, 分配1024大小的內存塊,並把內存地址壓入棧 type = lua_type(L, -1); printf("userdata type = %d\n", type); if(lua_isuserdata(L, -1)) printf("--------userdata------\n"); lua_pushthread(L); //thread, 創建一個lua新線程,並將其壓入棧。lua線程不是OS線程 type = lua_type(L, -1); printf("thread type = %d\n", type); if(lua_isthread(L, -1)) printf("--------thread------\n"); lua_close(L); //關閉狀態機 return 0; }
lua_pushXXX:push*族api向棧頂壓入數據,比如lua_pushnumber壓入數值,lua_pushstring壓入字符串,lua_pushcclosure壓入c閉包。
lua_isXXX:is*族api判斷棧里指定位置的索引是否是指定類型,比如,lua_istable(L,-1)判斷棧頂位置的數據是否是表,lua_isuserdata(L,-1)判斷棧頂位置的數據是否是用戶數據等。
gcc -o main.o main.c /usr/local/lib/liblua.a -I/usr/local/include/ -lm -ldl
運行結果如下,對應lua.h中的類型定義。c與lua之間詳細的api介紹參照http://cloudwu.github.io/lua53doc/contents.html#contents