美文网首页
C Lua API-栈

C Lua API-栈

作者: 烫烫烫烫烫烫烫烫烫烫烫烫 | 来源:发表于2019-05-06 15:05 被阅读0次

    简介

    C API 是一组能使用C代码与Lua交互的函数。其中包括读写Lua全局变量、调Lua函数、运行一段Lua代码,以及注册C函数以供Lua代码调用等。

    Lua和C语言之间的数据交换使用了一个抽象的栈。栈中的每个元素都能保存任何类型的Lua值。要获取Lua中的一个值时,只要调用一个Lua API函数,Lua就将指定的值压入栈中。要将一个值传给Lua时,需要现将这个值压入栈,然后调用Lua API,Lua就会获取该值并将其从栈中弹出。

    压入元素

    对于每种可以呈现在Lua中的C类型,API都有一个对应的压入函数。

    void lua_pushnil(lua_State* L); //常量nil
    void lua_pushboolean(lua_State* L, int bool); //bool 值
    void lua_pushnumber(lua_State* L, lua_Number n); //双精度浮点数
    void lua_pushinteger(lua_State* L, lua_Interger); //整数
    void lua_pushlstring(lua_State* L, const char* s, size_t len); //任意字符串,及其长度,包含任意二进制数据
    void lua_pushnil(lua_State* L, const char* s); //以0结尾的字符串
    

    对于Lua持有的字符串,它都会生成一个内部副本,或者复用现有内容。因此,即使在这些函数返回后立即释放或者修改这些字符串,都不会出问题。

    向栈中压入一个元素时,应该确保栈中具有足够的空间。启动Lua时,或者Lua调用C语言时,栈中至少会有20个空闲的槽(lua.h中的LUA_MINSTACK定义的)。一般情况时是够用的。如果有些情况需要更多的栈空间,就要调用lua_checkstack来检查是否有足够的空间

        int lua_checkstack(lua_State* L, int sz)
    

    查询元素

    栈索引

    API使用索引来引用栈中元素。第一个压入栈的元素索引为1,第二个则为2。同时也可以使用复数来作为索引访问栈中元素。-1则表示最后一个压入栈的元素,即栈顶元素,-2表示栈顶下面的一个元素,以此类推。

    检查元素类型

    为了检查一个元素是否为特定类型,API提供了一系列的函数lua_is*,其中*可以是任意Lua类型。这些函数有 lua_isnumber、lua_isstring、lua_istable等。
    实际上,lua_isnumber不会检查值是否为数字类型,而是检查是否能转换为数字类型。lua_isstring也有同样的行为。因此,对任意数字 lua_isstring 都返回真。

    查看元素类型

    lua_type 会返回赵中元素的类型。每种类型都对应一个常量,这些常量定义在头文件lua.h中。他们是

    LUA_TNIL
    LUA_TBOOLEAN
    LUA_TNUMBER
    LUA_TSTRING
    LUA_TTABLE
    LUA_TTHREAD
    LUA_TUSERDATA
    LUA_TFUNCTION
    

    另外,若要检查一个元素是否为真正的数字或者字符串(无须转换的),可以使用下列函数:

        int lua_toboolean(lua_State* L, int index)
        lua_Number lua_tonumber(lua_State* L, int index)
        lua_Interger lua_tointerger(lua_State* L, int index)
        const char* lua_tokstring(lua_State* L, int index, size_t *len) //len 字符串长度
        size_t lua_objlen(lua_State* L, int index) 
    
    

    如果指定的元素具有不正确的类型,调用这些函数也不会有问题。这种情况下, lua_toboolean、lua_tonumber、lua_tointerger、lua_objlen 会返回0,其他函数返回NULL。
    lua_tolstring 函数会返回一个只想内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。这个内部副本不能修改。lua保证只要这个对应的字符串的值还在栈中,那么这个指针就是有效的。当Lua调用的一个C函数返回时,Lua就会情况它的栈。所以不要在C函数之外使用C函数内部获得的指向Lua字符串的指针。

    lua_objlen函数可以返回一个对象的长度"长度",对于字符串和table这个值是操作符 "#" 的结果。这个函数还可以用于获取一个完全userdata(full userdata)的大小。
    下面的方法可以定义栈中的值的类型:

    static void stack_dump(lua_State *L) {
        int i;
        int top = lua_gettop(L);//获取栈顶元素索引
        for (i = 1; i <= top; i++) {
            int t = lua_type(L, i);
            switch (t) {
            case LUA_TSTRING: {
                printf("'%s'", lua_tostring(L, i));
                break;
            }
            case LUA_TBOOLEAN: {
                printf(lua_toboolean(L, i) ? "true" : "false");
                break;
            }
            case LUA_TNUMBER: {
                printf("'%g'", lua_tostring(L, i));
                break;
            }
            default:
                printf("%s", lua_typename(L, t));
                break;
            }
        }
    }
    
    

    其他栈操作

    除了在C语言和栈之间数据交换函数之外,API还提供了一下用于普通栈操作的函数

        int lua_gettop(lua_State* L);
        void lua_settop(lua_State* L, int index);
        void lua_pushvale(lua_State* L, int index);
        void lua_remove(lua_State* L, int index);
        void lua_insert(lua_State* L, int index);
        void lua_replace(lua_State* L, int index);
    

    lua_gettop : 函数返回栈中元素个数,也可以所示栈顶元素的索引。
    lua_settop :将栈顶设置为指定位置

    如果之前的栈比型的栈顶要高,那么高出来的元素会被丢弃。反之,会向栈中压入nil来补足大小。
    API函数还提供了一个宏用于从栈中弹出n个元素
    #define lua_pop(L,n) lua_settop(L, -(n) -1)

    lua_pushvalue: 函数会将指定索引上的值的副本压入栈。
    lua_remove: 删除指定索引上的元素,并将位置之上的所有元素下一填补空缺
    lua_insert: 会上移指定位置之上的所有元素一开辟一个槽的空间,然后将栈顶元素移到改位置
    lua_replace: 弹出栈顶的值,并将改值设置到指定索引上,当它不会移动任何东西

    示例:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #ifdef __cplusplus
    extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    }
    
    #endif // __cplusplus
    
    
    static void stack_dump(lua_State *L) {
        int i;
        int top = lua_gettop(L);//鑾峰彇鏍堥《鍏冪礌绱㈠紩
        for (i = 1; i <= top; i++) {
            int t = lua_type(L, i);
            switch (t) {
            case LUA_TSTRING: {
                printf("'%s'", lua_tostring(L, i));
                break;
            }
            case LUA_TBOOLEAN: {
                printf(lua_toboolean(L, i) ? "true" : "false");
                break;
            }
            case LUA_TNUMBER: {
                printf("%g", lua_tonumber(L, i));
                break;
            }
            default:
                printf("%s", lua_typename(L, t));
                break;
            }
            printf("  ");
        }
        printf("\n");
    }
    
    
    int main() {
    
        lua_State* L = luaL_newstate();
    
        lua_pushboolean(L, 1); //1
        lua_pushnumber(L, 10);//2
        lua_pushnil(L);//3
        lua_pushstring(L, "hello world");//4
    
        stack_dump(L);
    
        lua_pushvalue(L, -4); //true  10  nil  'hello world'  true    娣诲姞浜嗕竴涓?true
        stack_dump(L);
    
        lua_replace(L, 3);  // true  10  true  'hello world'
        stack_dump(L);
    
        lua_settop(L, 6); //true  10  true  'hello world'  nil  nil
        stack_dump(L);
    
        lua_remove(L, -3); //true  10  true  nil  nil
        stack_dump(L);
    
        lua_settop(L, -5); //true
        stack_dump(L);
    
        lua_close(L);
        system("pause");
    }
    

    相关文章

      网友评论

          本文标题:C Lua API-栈

          本文链接:https://www.haomeiwen.com/subject/jmaroqtx.html