C与lua
来源:互联网 发布:efe矩阵ife矩阵哪个先 编辑:程序博客网 时间:2024/05/19 02:20
c api
lua是一种嵌入式语言,可以链接到其他车型的库,lua库看拓展内容 使用了lua的程序可以注册其他语言的函数来向lua 添加功能
c api 是一组能是c代码与lua 交换的函数, 包括 读写lua全局变量, 调用lua函数 ,运行lua 代码 注册 c函数给lua调用
lua 与 c 通信的主要方法是一个无处不在的虚拟栈, 所有api都会操作这个栈上的值,所有交换都在c与lua的差异都在栈上解决
c 中调用lua
#include<stdio.h>#include<string.h>#include<lua.h>#include<luaxlib.h>#include<lualib.h>int main(void){ char buff[256]; int error; lua_State* L = luaL_newstate() /*打开lua*/ luaL_openlibs(L); /* 打开标准库 */ while(fgets(buff, sizeof(buff), stdin) != NULL) { /* pcall 调用lua 函数*/ error = luaL_Loadbuffer(L, buff, strlen(buff), "line") || lua_pcall(L, 0, 0, 0); if(error) { fprintf(stderr, "%s", lua_tostring(L, -1)); lua_pop(L, 1); /*从栈上获取错误信息*/ } } lua_close(L); return 0;}
lua.h
提供创建lua环境调用lua函数的函数 读写lua 环境中的全局变量以及注册c函数给lua调用,以lua_为前缀
luaxlib.h 定义了辅助库,以luaL_ 为开头, lua 库没有全局变量 都在一个 lua_State 之中 所有的api都要传入该结构体
luaL_newState() 创建了一个新的lua 环境,其中没有任何函数(print都没有)需要 luaL_openlib() 来打开标准库
创建好state 之后 可以使用luaL_loadbuffer 来编译输入内容,并想栈压入程序块,任何调用lua_pcall
如果发生错误会向栈压入错误信息,可以使用lua_string()来获取 并打印,最后调用lua_pop 删除信息
栈
lua 与c++直接数据交换需要考虑类型,内存管理的区别
lua使用了一个抽象的栈来保存数据,栈上保存任何类型的lua的值
———————->
先进先出
压入栈
c类型都有一个压栈函数
// c 向lua 栈添加元素void lua_pushnil(lua_State* L);void lua_pushboolean(lua_State* L, int bool);void lua_pushnumber(lua_State* L, lua_Number n);//double 类型void lua_pushinteger(lua_State* L, lua_Integer n);void lua_pushlstring(lua_State* L, const char* s, size_t len);//任意长度的字符串void lua_pushstring(lua_State* L, const char* s);//以0结尾的字符串
栈至少会有20 个空槽
lua_checkstack()检查栈是否有足够的空间
查询元素
lua api 使用整数索引来引用栈元素,第一个压入的元素索引是1 第二个为2 知道栈顶 也可以以栈顶为开始以负数为为索引来查询元素
-1 表示栈顶, -2表示下面的一个
调用lua_tostring(L, -1)会将栈顶元素作为字符串返回
使用lua_is*(lua_State* L, int index) 来检测类型
*代表number string table等
isnumber 和isstring 会检测lua变量能否转化为对应类型 使用对于数字 isstring 为真
以下函数来获取栈内元素
LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);LUA_API int (lua_toboolean) (lua_State *L, int idx);LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);LUA_API size_t (lua_objlen) (lua_State *L, int idx);LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);LUA_API void *(lua_touserdata) (lua_State *L, int idx);LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);LUA_API const void *(lua_topointer) (lua_State *L, int idx);
其余栈操作
int lua_gettop(lua_State* L); // 返回栈中元素个数 注意是个数也就是栈顶的索引 具体值使用上面函数获取void lua_settop(lua_State* L, int index);// 修改栈顶索引也就是修改栈内元素数量 这样的修改会丢去多余 及补充nilvoid lua_pushvalue(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的情况
作为配置
luaL_loadfile(Lua_State* L, const char* fname); // 加载lua文件lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);// 执行lua 如果发生错误会把一个错误消息压入栈给c api获取处理lua_getglobal(L, fieldName)// 获取lua全局变量压入栈 会将lua的全局变量压入栈并给c pi调用
加载并且读取lua 程序使宿主程序可以不修改而达到目的, 同时lua作为编程语言还可以执行逻辑运算等,可以让配置更清晰方便
table操作
lua table 操作函数只有一个lua_gettable() 需要知道table的位置,以及key,就能压入value 弹出key
background = { r = 255, g = 144, b = 122 }
以下函数假定目标table 在栈顶(-1位置)//对于5.1之后的lua 获取table的操作可以简化为//获取table属性值lua_getfield(L, -1, key); //字符串没有压入栈所以 -1 是table的索引//等价于lua_pushstring(L, key); lua_gettable(L, -2);/*****************/// 修改table属性值lua_pushnumber(L, value);lua_setfield(L, -2, index);// 会弹出value// 等价于lua_pushstring(L, index);lua_pushnumber(L, value);lua_settable(L, -3);// 对于不同类型只需要使用对应的函数替代即可
创建一个lua table
lua_newtable(L);// 创建tablelua_pushnumber(L, value); lua_settable(L, -2, index);// 创建table属性...lua_setglobal(L, tName);// 赋值到 lua全局变量会弹出table
调用lua函数
c调用lua函数只需要将函数载入到栈中并压入参数即可完成调用
lua_getglobal(L, "f"); // 全局变量中获取函数变量并且压入栈lua_pushnumber(L, x); // 压入一个参数 lua_pushnumber(L, y); // 压入第二个参数// 调用lua函数, 2个参数 || 1个返回值 || 错误处理函数索引 栈中的函数索引 0代表没有if(lua_pcall(L, 2, 1, 0) != 0) // 此调用会弹出函数及参数 error(L, "error running function %s", lua_tostring(L, -1));// 查看函数调用结果if(!lua_isnumber(L, -1)) error(L, "function return error type")int z = lua_tonumber(L, -1);lua_pop(L, 1); // 弹出返回值return z;
从lua到c
使用lua来拓展程序,还可以将c的函数注册到lua中
lua调用c也使用了一个c调用lua相同的栈,c函数从栈获取函数参数,并且将结果压入栈,以及结果数量,
栈不是全局的结构,每个函数都有自己的局部私有栈,lua调用c时第一个参数总是局部栈的索引1,
c函数
所有的注册到lua的c函数都有相同的原型,
static int l_sin(lua_State* L){ double d = luaL_checknumber(L, 1); // get arg with type check lua_pushnumber(L, sin(d)); // push return return 1;}typedef int (*lua_CFunction) (lua_State* L); // 返回值表示压入栈的返回值数量, 函数返回后会自动删除栈中结果// 注册函数lua_pushcfunction(L, l_sin);// 添加为全局变量lua_setglobal(L, "mysin");
c 模块 (注册到lua module)
// 定义函数static int l_dir(lua_State* L){ //...}static const struct lua_Reg mylib[] = { //FUNC NAME func pointer {"dir", l_dir}, {NULL, NULL},}// 注册module到lualuaL_register(L, "mylib", myLib);
最后将c代码编译成动态链接库加入path之中即可使用
在lua中只要使用require就可以获取对应module的table
require “mylib”
数组操作
数组是编程中使用最广泛的数据结构,为了方便与性能,lua为数组提供了专用函数,在lua 数组就是table
// table 栈上位置 table的索引void lua_rawgeti(lua_State* L, int index, int key);//<==>lua_pushnumber(L, key); // 压入table索引值lua_rawget(L, t);// 从栈上的位置找到table 并且以栈顶的索引访问table并且返回值void lua_rawseti(lua_State* L, int index, int key);//<==>lua_pushnumber(L, key);// 压入table索引值lua_insert(L, -2);// 把key插入到前值之后,lua_rawset(L, t)// 插入table//exampleint l_map(lua_State* L){ int i, n; lua_checktype(L, 1, LUA_TTABLE); lua_checktype(L, 2, LUA_TFUNCTION); n = lua_objlen(L, 1);// get table size for(i = 1, i <= n; i++) { lua_pushvalue(L, 2);//压入function lua_rawgeti(L, 1, i);// 获取到table的成员t[i]并压入栈 lua_call(L, 1, 1);//调用 function(t[i]) lua_rawseti(L, 1, i);// t[i] = call result } return 0;// 函数不向lua返回值}
总结
c 与lua的交互都在一个栈上,c调用lua根据栈上值的信息完成读取lua数据,调用lua函数等操作,lua调用c主要是绑定函,从栈获取参数并将结果压入栈。
- 【Lua】Lua与C交互
- lua与c互调--c调用lua
- lua与c互调--lua调用c
- Lua 与C交互
- Lua 与 C 交互
- Lua与C混编
- lua与C/C++
- Lua 与C交互
- Lua 与C交互
- Lua 与C交互
- Lua 与 C 交互
- lua与c交互
- C与lua交互
- Lua与C
- Lua与C交互
- C与lua
- lua与c交互
- lua与C++ / Lua 与C交互
- 【Linux】Linux进程间通信——使用消息队列
- MySQL replace
- socket网络编程中read与recv区别
- [leetcode]: 172. Factorial Trailing Zeroes
- Uity开发随笔(一)
- C与lua
- 制作initramfs/initrd镜像
- 10.重载示例(上)
- HDU3974-Assign the task(线段树+区间建树)
- CaffeOnSpark安装和使用教程系列二:单节点使用CaffeOnSpark进行MNIST数据集的测试
- c++与lua
- 【C#机房重构】命名空间"Microsoft"中不存在类型或命名空间名称"Office"(是否缺少程序引用?)
- 安装完jdk,重新部署项目启动时,提示找不到jre解决方案
- UVa 11384 Help is needed for Dexter——思路题