lua C API(1) - 函数汇总

2018-08-31 14:15:21

在调用C API时有几个重要的头文件:

lua.h:
    基础函数库,lua_ 前缀。

lauxlib.h
    辅助库,luaL_ 前缀,利用 lua.h 实现的更高层的抽象。

lualib.h
    为了保持Lua的苗条,所有的标准库以单独的包提供,所以如果你不需要就不会强求你使用它们。头文件 lualib.h 定义了打开这些库的函数。 例如,调用luaopen_io,以创建io table并注册I/O函数(io.read,io.write等等)到Lua环境中。

基础函数库

对栈里 index 处的元素类型判断,成功返回1,失败返回0。

//数字或者可以转换成数字的字符串
int lua_isnumber (lua_State *L, int index);

//数字或者字符串
int lua_isstring (lua_State *L, int index);

//指定index出栈元素是否为布尔
int lua_isboolean (lua_State *L, int index);

//表格
int lua_istable (lua_State *L, int index);

//c函数
int lua_iscfunction (lua_State *L, int index);

//c或者lua函数
int lua_isfunction (lua_State *L, int index);

//nil
int lua_isnil (lua_State *L, int index);

//无效数据,比如引用到到栈外
int lua_isnone (lua_State *L, int index);

//nil或者无效数据
int lua_isnoneornil (lua_State *L, int index);

//线程
int lua_isthread (lua_State *L, int index);

//light userdata
int lua_islightuserdata (lua_State *L, int index);

//full or light userdata
int lua_isuserdata (lua_State *L, int index);

判断并获取堆栈上的值

//false,nil,无效数据 等返回0,其他返回1
int lua_toboolean (lua_State *L, int index);

//转换为c函数,如果不是c函数返回NULL
lua_CFunction lua_tocfunction (lua_State *L, int index);

//转化为有符号整型,必须为数字或者可转化为数字的字符串,否则返回0
//如果为非整型数字,会被截断
lua_Integer lua_tointeger (lua_State *L, int index);

//如果len不为NULL,那么len设置为字符串长度,返回的字符串以\0结尾,该字符串中间也可以包含\0.
//lua可能会发生垃圾回收,所以不保证返回的字符串任然有效
const char *lua_tolstring (lua_State *L, int index, size_t *len);
//等效于上面len设置为NULL
const char *lua_tostring (lua_State *L, int index);

//转化为数字,必须为数字或者可转化为数字的字符串,否则返回0
lua_Number lua_tonumber (lua_State *L, int index);

//转化为指针,可以为userdata, a table, a thread, function
//否则返回NULL,一般用来调试
const void *lua_topointer (lua_State *L, int index);

//转化为线程,否则返回NULL
lua_State *lua_tothread (lua_State *L, int index);

//如果为userdata,返回块地址,如果为light userdata,返回指针
//否则返回NULL
void *lua_touserdata (lua_State *L, int index);

判断类型

//返回数据类型,为类型常量
//LUA_TNONE 无效数据
//LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION
//LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA
int lua_type (lua_State *L, int index);

函数调用

/*
    调用函数,调用的函数必须先压入栈,然后以此压入函数参数,nargs为压入栈的参数个数。
    当函数调用完毕后,函数及所有参数都会出栈。函数的返回值将会入栈,调整为 nresults 个,
    除非 nresults 被设置为 LUA_MULTRET。
    第一个返回参数先进栈,因此调用结束后,最后一个返回值在栈顶。
    发生错误将(通过 longjmp)一直上抛
*/
void lua_call (lua_State *L, int nargs, int nresults);

/*
    以保护的模式运行函数,如果没有报错,行为和 lua_call 一致,如果发生错误,从栈顶移除函数和参数,
    并压入错误字符串并返回错误码。
    如果errfunc为非0,那么错误字符串不会压入栈顶而是当做参数传递给 errfunc,返回的字符串将压入栈顶作为错误字符串。
    调用成功返回0,否则返回如下一种
    LUA_ERRRUN:运行时错误
    LUA_ERRMEM:内存分配错误,该错误 lua 调用不了错误处理函数
    LUA_ERRERR:在运行错误处理函数时发生错误
*/
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

压入栈

//把b当做布尔值压入栈
void lua_pushboolean (lua_State *L, int b);

//压入一个闭包函数
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

//压入一个c函数
//#define lua_pushcfunction(L,f)  lua_pushcclosure(L,f,0)
void lua_pushcfunction (lua_State *L, lua_CFunction f);

//压入格式化后的字符串,返回字符串指针
//1.无需分配内存,lua帮我们做,通过垃圾回收释放。
//支持%%,%s,%f,%d,%p,%c
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

//类似于上面,只是利用 va_list 接收参数
const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);

//把n作为整数压入栈
void lua_pushinteger (lua_State *L, lua_Integer n);

//把一个 light userdata 压入栈
//userdata 在lua 中标识一个 C 值,light userdata 标识一个指针,它是一个像数字一样的值,你不需要专门创建它
//它也没有独立的 metatable,而且也不会被垃圾回收(因为没创建过)。只要表示的 C 地址相同,两个 light userdata 
//就相同。
void lua_pushlightuserdata (lua_State *L, void *p);

//把指针s指向的长度为 len 的字符串(字符串中间可以包含\0)压入栈,lua 会对这个字符串做内存拷贝或是复用一个拷贝,
//因此函数返回后,s内存可以释放或者做其他用途。
void lua_pushlstring (lua_State *L, const char *s, size_t len);

//类似于上面,只是s中间不能包含\0,遇到的第一个 \0 当做是字符串的结束。
void lua_pushstring (lua_State *L, const char *s);

//把一个 nil 压入栈
void lua_pushnil (lua_State *L);

//把数字压入栈
void lua_pushnumber (lua_State *L, lua_Number n);

//压入线程,如果为主线程,返回1
int lua_pushthread (lua_State *L);

//把指定 index 处的元素做拷贝压入栈
void lua_pushvalue (lua_State *L, int index);

//把栈顶元素插入到栈指定 index 处,并依次移动这个索引之上的元素。不能用伪索引,
//因为伪索引不是真正指向堆栈上的位置。
void lua_insert (lua_State *L, int index);

get 相关操作

//把索引处值的环境表压入堆栈
void lua_getfenv (lua_State *L, int index);

//把 t[k] 值压入堆栈,这里的 t 是有效索引 index 指向的值,可能触发元表的__index元方法
void lua_getfield (lua_State *L, int index, const char *k);

//把全局变量 name 里的值压入堆栈。它是一个宏定义
//#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
void lua_getglobal (lua_State *L, const char *name);

//把给定索引指向的值的元表压入堆栈,如果索引无效,或是这个值没有元表,函数将返回 0 并且不会向栈上压任何东西。
int lua_getmetatable (lua_State *L, int index);

//把 t[k] 的值压入堆栈,这里的 t 是有效索引 index 指向的值,而 k 是栈顶的值
//这个函数会弹出堆栈上的 key 并把结果压入堆栈,可能触发元表的__index元方法
void lua_gettable (lua_State *L, int index);


//返回栈顶元素的索引,因为索引从1开始编号,所以等于栈上元素个数
//因此0表示堆栈为空
int lua_gettop (lua_State *L);

其他堆栈操作

/*
假设栈里有2个元素。
如果index=0,那么移除栈上所有元素
如果index=1,移除栈顶一个元素
如果index=4,那么压入2个nil元素
*/
void lua_settop (lua_State *L, int index);

//从栈里弹出n个元素
void lua_pop (lua_State *L, int n);

//移除指定栈的元素,该栈上面的元素调整下移
void lua_remove (lua_State *L, int index);

//把栈顶元素移动到指定栈,该栈以上的元素上移
void lua_insert (lua_State *L, int index);

//把栈顶的元素替换到指定栈的元素
void lua_replace (lua_State *L, int index);

set 相关操作

/*
把栈顶的元素弹出并设置为指定栈表格下标为k的值,可能触发元表__newindex元方法。
*/
void lua_setfield (lua_State *L, int index, const char *k);

// 弹出一个元素并把该值设置到全局变量 name 上,宏定义如下
// #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
void lua_setglobal (lua_State *L, const char *name);

//弹出表格并设置为指定栈元素的元表
int lua_setmetatable (lua_State *L, int index);

//栈顶当做值,栈顶下面的元素当做key设置到指定栈的表格里,并弹出这2个元素,可能触发元表__newindex元方法。
void lua_settable (lua_State *L, int index);

协程,多个协程其实就是多个独立的栈。

/*
    类似于 lua_pcall,首先压入函数,然后压入参数,最后调用,narg代表调用参数个数。
    1.lua_resume 不需要返回参数个数标记,总是返回所有该函数返回值
    2.没有错误处理函数,发生错误不会改变栈,所以出错后可以检查栈。
    3.如果调用的函数 yields,lua_resume 返回状态码 LUA_YIELD,并标记该协程后面可以被重新运行(resume)
    
    当返回 LUA_YIELD,协程的栈可见部分为传递给 yield 的值。lua_gettop 返回被 yield 的值的数量。
    一般我们可以利用 lua_xmove 把这些值移动到其他协程。
    
    想要重新运行被挂起的协程,可以再次调用 lua_resume,此时 lua 会把栈里的所有值当做 yield 返回。
    比如你如果在两次调用 lua_resume 之间不改变栈,那么 yield 将会返回它自己传递的值。
    
*/

//返回1(LUA_YIELD)代表遇到 yield,返回 0 代表协程完成,其他代表出错。
int lua_resume (lua_State *L, int narg);
/*
    声明一个 state,里面自动会生成一个协程,称为主协程,这个主协程不会被垃圾回收
    它会跟 state 一起释放比如调用 lua_close。
*/
lua_State* L = luaL_newstate();

/*
    当然我们可以在此基础上创建另外一个协程,调用如下方法,此时,主协程的栈顶会压入一个新协程,
    L,L1属于同一个 state,只是它们拥有自己独立的栈。
    L1 刚创建时栈是空的,而 L 的栈顶为 L1 协程。
*/
L1 = lua_newthread(L);

printf("%d\n", lua_gettop(L1)); --> 0,代表栈为空
printf("%s\n", luaL_typename(L, -1)); --> thread

/*
    注意,除了主协程,其他协程都会被垃圾回收器所监控。
    当我们创建新协程,该协程会被压入主协程的栈顶来标记该协程不能被垃圾回收。我们绝不能使用不在主协程栈里的协程。
    一些调用 lua api 的动作可能会促使不在主协程栈里的协程被回收。
*/

lua_State *L1 = lua_newthread(L);  //创建新协程
lua_pop(L, 1);    //弹出新协程,此时该协程被标记为垃圾
lua_pushstring(L1, "hello");  //可能会触发垃圾回收,避免这样做

其他

//操作同一个 state 里的两个协程
//从 from 栈里弹出n个元素压入 to 栈
void lua_xmove (lua_State *from, lua_State *to, int n);


辅助库

加载lua代码 

//下面两个函数只会加载代码块而不会运行
/*
从内存 buff 出加载长度为sz的lua代码块,name是代码块名称用于调试
返回值如下:
0:成功
LUA_ERRSYNTAX:预编译语法错误
LUA_ERRMEM:内存分配错误
*/
int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);

//从以 \0 为结束符的字符串里加载代码块,其他同上
int luaL_loadstring (lua_State *L, const char *s);

/*
从指定文件加载代码块,如果filename为NULL,则从标准输入获取,如果第一行为#开头则忽略
返回值同上,并额外多出一个
LUA_ERRFILE:代表不能打开或读取指定文件
*/
int luaL_loadfile (lua_State *L, const char *filename);


void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l);

如果 libname 为 NULL,只是简单的注册 l 里所有的函数到栈顶的表格里。

如果 libname 不为 NULL,会创建一个新表格 t,全局变量 libname 和 package.loaded[libname] 都指向该表格,并把所有的 l 里的函数注册到它上面。如果 package.loaded[libname] 或者 libname 变量已经指向了一个表格,那么会重用而不会新创建表格 t。该函数会把表格放在栈顶。

/*
    如果registry[tname] 已存在,返回 0,否则创建一个元表(将来给 userdata 用)赋给 registry[tname],返回1
*/
int luaL_newmetatable (lua_State *L, const char *tname);

//把 registry[tname] 指向的元表压入栈
void luaL_getmetatable (lua_State *L, const char *tname);

//判断栈里索引为narg的参数的元表是否为 registry["LuaBook.array"],如果不是则报错
//是返回 userdata 指针地址
void *luaL_checkudata (lua_State *L, int narg, const char *tname);


备注:

1.本文只是对模块加载机制做简单的介绍,如果有疑问可以给我留言
2.lua的版本为5.1,运行环境centos7 64位
3.原文地址http://www.freecls.com/a/2712/100


©著作权归作者所有
收藏
推荐阅读
  • lua模块安装

    lua模块安装可以利用 luarocks 命令,在centos7 上执行以下来安装。yum install epel-release yum install luarocks此时我们安装模块的的时候可...

  • lua coroutine(协程)

    协程相关的文章网上有很多,众说纷坛,相比其他技术概念理解起来没那么直接。因为协程涉及了很多底层高并发概念,没接触过操作系统调度,C语言等底层知识根本不可能完全理解。备注:以下我说的单进程就是指一个进程...

  • lua模拟面向对象编程

    lua中跟对象和类最像的就是表格有方法和属性,所以类和对象都只能用表格来模拟声明一下,其实表格的功能已经能应付大部分场景了,而且lua脚本语言本就不是面向对象语言(它的优势是轻量级简单快速),硬要模拟...

  • lua元表

    lua元表其实就是为了扩展表格间的运算,比如之前我们如果让2个表格相加就会报错,一旦我们设置了元表并加上了__add属性,那么就会正常执行。先看2个元表相关的函数setmetatable(table,...

  • lua模块编写

    lua允许我们编写自定义模块以便后面调用,在编写模块之前我们先认识2个知识点1.lua语言中数组,模块其实都是table表格。2.在之前的lua基本语法里我们知道函数是可以赋值给变量的好,我们新建一个...

  • nginx模块 ngx_http_headers_module

    ngx_http_headers_module 模块是用来增加 Expires 和 Cache-control,或者是任意的响应头。Syntax: add_header name value [alw...

  • nginx模块 ngx_http_gunzip_module、ngx_http_gzip_module、ngx_http_gzip_static_module

    ngx_http_gunzip_module 模块将文件解压缩后并在响应头加上 "Content-Encoding: gzip" 返回给客户端。为了解决客户端不支持gzip压缩。编译的时候带上 --w...

  • nginx模块 ngx_http_flv_module、ngx_http_mp4_module

    ngx_http_flv_module模块提供了对 flv 视频的伪流支持。编译的时候带上 --with-http_flv_module。它会根据指定的 start 参数来指定跳过多少字节,并在返回数...

  • nginx模块 ngx_http_fastcgi_module

    ngx_http_fastcgi_module 模块使得nginx可以与 fastcgi 服务器通信。比如目前要使得 nginx 支持 php 就得使用 fastcgi技术,在服务器上装上 nginx...

  • nginx模块 ngx_http_autoindex_module

    ngx_http_autoindex_module 模块可以将uri以 / 结尾时,列出里面的文件和目录。Syntax: autoindex on | off; Default: autoindex ...

简介
天降大任于斯人也,必先苦其心志。