zoukankan      html  css  js  c++  java
  • 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
    ", type);
        if(lua_isnil(L, -1)){
            printf("------nil-----
    ");
        }
    
        lua_pushboolean(L, 0); //boolean
        type = lua_type(L, -1);
        printf("boolean type = %d
    ", type);
        if(lua_isboolean(L, -1))
            printf("--------boolean------
    ");
    
        lua_pushlightuserdata(L, NULL); //lightuserdata
        type = lua_type(L, -1);
        printf("lightuserdata type = %d
    ", type);
        if(lua_islightuserdata(L, -1))
            printf("--------lightuserdata------
    ");
    
        lua_pushnumber(L, 10); //number
        type = lua_type(L, -1);
        printf("number type = %d
    ", type);
        if(lua_isnumber(L, -1))
            printf("--------number------
    ");
    
        lua_pushstring(L, "string"); //string
        type = lua_type(L, -1);
        printf("string type = %d
    ", type);
        if(lua_isstring(L, -1))
            printf("--------string------
    ");
    
        lua_newtable(L); //table, 创建空表,并压入栈
        type = lua_type(L, -1);
        printf("table type = %d
    ", type);
        if(lua_istable(L, -1))
            printf("--------table------
    ");
    
        lua_newuserdata(L, 1024); //userdata, 分配1024大小的内存块,并把内存地址压入栈
        type = lua_type(L, -1);
        printf("userdata type = %d
    ", type);
        if(lua_isuserdata(L, -1))
            printf("--------userdata------
    ");
    
        lua_pushthread(L); //thread, 创建一个lua新线程,并将其压入栈。lua线程不是OS线程
        type = lua_type(L, -1);
        printf("thread type = %d
    ", type);
        if(lua_isthread(L, -1))
            printf("--------thread------
    ");
    
        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

     

  • 相关阅读:
    20165212第八周学习总结
    20165212第八周课上测试补做
    20165212实验二面向对象程序设计
    Titanic生存预测
    聚类算法数据生成器make_blobs
    k-means
    监督学习、无监督学习与半监督学习
    在线Latex公式编辑器
    西瓜书课后习题——第四章
    ML经典数据集
  • 原文地址:https://www.cnblogs.com/RainRill/p/8361011.html
Copyright © 2011-2022 走看看