Lua C API 交互

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lingdi2000/article/details/89883253

lua程序设计第二版笔记

简介

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");
}

猜你喜欢

转载自blog.csdn.net/lingdi2000/article/details/89883253
今日推荐