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

 

posted on 2018-02-01 17:59  RainRill  阅读(9075)  评论(0编辑  收藏  举报

导航