C Lua API-栈

简介

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");
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351