lua與c之間交互詳解(一)


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM