美文网首页
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-栈

    简介 C API 是一组能使用C代码与Lua交互的函数。其中包括读写Lua全局变量、调Lua函数、运行一段Lua代...

  • 2019-01-14

    Lua与C交互学习笔记 Lua与C交互是通过虚拟栈实现的 在C中调用Lua 方法一 栈中的情况如下表所示 方法二 ...

  • LuaC API

    Lua C APi 总结 Lua_newtable(L) 创建table并放到栈顶 lua_pushstring(...

  • Lua与C数据交互一

    C与Lua的数据交互,是通过虚拟栈来完成数据交互的,在C与Lua之间的交互,实际上是C与虚拟栈之间的交互以及Lua...

  • Lua和C交互的简易教程

    Lua栈 要理解Lua和C++交互,首先要理解Lua堆栈。简单来说,Lua和C/C++语言通信的主要方法是一个无处...

  • Lua api(七) lua_remove/lua_replac

    前言# 初步了解过lua的人都知道,lua和c交互式通过虚拟栈来实现的,这个栈造就了lua的神奇,那么我们今天来看...

  • Lua与C++如何相互交互?

    Lua与C++如何相互交互 通过lua虚拟栈隔离Lua和C/C++类型和彼此内存的差异来实现数据及函数互相调拥。1...

  • lua 和 c 交互

    Q:什么是Lua的虚拟栈? A:C与Lua之间通信关键内容在于一个虚拟的栈。几乎所有的调用都是对栈上的值进行操作,...

  • Goroutine 随笔

    很早之前在lua中实现过一版协程,lua的栈是虚拟的,当要切换协程时虚拟栈不需要退栈,只需要从C的栈(物理栈)退出...

  • C模块回调Lua函数的两种方法

    lua和C通过虚拟栈这种交互方式简单而又可靠,缺点就是C做栈平衡稍微会多写一点代码。今天分享学到的C模块回调Lua...

网友评论

      本文标题:C Lua API-栈

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