lua Capi
一、C环境使用mingw 的gcc
可从这里下载完整版那的mingw: http://pan.baidu.com/s/1crx1s
可参考该设置环境变量及编译lua的教程:https://www.cnblogs.com/jessicas/articles/4477655.html?tdsourcetag=s_pctim_aiomsg
lua要使用该mingw进行编译;记住不要使用5.1.5版本的lua;编译会有问题
我使用sublime进行编码,可以设置如下的编译配置:
{ "working_dir": "$file_path", "cmd": "gcc -Wall \"$file_name\" -o \"${file_base_name}.exe\" -llua", "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", "selector": "source.c", "variants": [ { "name": "Run", "shell_cmd": "gcc -Wall \"$file_name\" -o \"${file_base_name}.exe\" -llua && start cmd /c \"\"${file_path}/${file_base_name}.exe\" & pause\"" } ] }
二、lua跟c之间的参数传递使用的是栈的方式:fifo
关于lua栈的操作方法有如下testStack里面用到的;
void stackDump(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"); } void TestStack(lua_State* L) { lua_pushboolean(L, 1); lua_pushnumber(L, 10); lua_pushnil(L); lua_pushstring(L, "hello"); stackDump(L); lua_pushvalue(L, -4); // 插入从栈顶往下数第四个对应的那个值 stackDump(L); lua_replace(L, 3); // 将栈顶的值取出,替换从栈底往上数第三个的值 stackDump(L); lua_settop(L, 6); // 将栈的大小设置为6;如果之前栈大于6,则变成6;如果之前栈小于6,则新增的栈的位置赋nil stackDump(L); lua_remove(L, -3); // 移除从栈顶往下数,第三个的栈值 stackDump(L); // lua_settop(L, -5); // 相当于删除栈顶的5个元素 lua_insert(L, -4); // 将栈顶的值取出插入到从栈顶往下数第四个的位置;则之后的三个值网上移。注意这个跟lua_replace的区别 stackDump(L); }
三、查询元素
有lua_is*(lua_State* L, int index) 查询对应的是什么类型的元素 lua_isnumber,lua_isstring, lua_istable等
isnumber判断的是该值能否转成数字,不一定是数字。所以对于任何数字,isstring一定是返回真。
查看类型有另外一个函数:lua_type 返回该类型,他们用常量代替;
获取值的有lua_tostring,lua_tolstring, 查看源码可以发现
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
lua_tostring是一个宏;
返回的是const char* 类型的;第三个参数可以返回字符串的长度;如下所示
const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
向查询当前栈中有多少个值,可以使用lua_gettop()函数
默认情况下lua的栈可以装20个值;如果任务比较多,可以使用
lua_checkstack这个函数来检查栈中是否有足够的空间。如果返回0则表示false,1则表示容纳的下。
三、调用lua自定义模块
void load(lua_State* L, const char* fname) { if (luaL_loadfile(L, fname) || lua_pcall(L,0,0,0)) error(L, "cannot run cfg file: %s", lua_tostring(L,-1)); }
首先需要先将文件load进来;然后调用pcall;这两个函数如果调用没有问题则会返回0,如果出现错误则会返回对应的错误代码,并将错误代码压入栈顶。
上面的函数当loadfile完成之后再调用pcall;
手册中明确提到,lua_load把一个文件当作一个chunk编译后放到stack的栈顶;
chunk就是一个可执行语句的组合,可以是一个文件也可以是一个string;
“Lua handles a chunk as the body of an anonymous function with a variable number of arguments” 这是Lua对chunk也就是lua文件的处理方式,就是认为是一个可变参数的匿名函数。也就是说,调用后栈上有一个匿名函数,这个函数的body就是文件中所有的内容。
在luaL_loadfile后,调用lua_getop以及lua_type可以知道栈的大小为1,放在栈上的是一个fucntion类型的value。为什么loadfile后我们不能直接获取到printmsg这个函数呢,那是因为刚才提到的,loadfile仅仅视编译lua文件,并不执行这个文件,也就是说只是在栈上形成了一个匿名函数。只有执行这个函数一次,才会使得printmsg可以通过lua_getglobal获取,否则,全局变量是空的。
Lua在执行函数的时候,函数会实例化,获得的closure也是这个函数的最终值。
具体可以查看:https://blog.csdn.net/liutianshx2012/article/details/44034421/
四、关于table的操作
获取lua中的table的value
lua_getglobal(L, "background"); // 将lua的全局table background压入栈顶,再获取background 这个table表中的value,如下
#define MAX_COLOR 255 int getfield(lua_State* L, const char* key) { int result; // lua_pushstring(L, key); // lua_gettable(L, -2); // 弹出栈顶的key,然后压入栈顶value lua_getfield(L, -1, key); // 上面注释的方式和当前的这种方式均能做到上述注释的操作。即栈顶为value if (!lua_isnumber(L, -1)) error(L, "invalid color"); result = (int)lua_tonumber(L, -1) * MAX_COLOR; lua_pop(L, 1); // 弹出栈顶的1个元素;如果为n,则为弹出n个元素,这里要注意如果是字符串的话,得先拷贝一份再弹出,因为弹出之后字符串内存被释放 return result; }
如下则是设置table的操作
void setfield(lua_State* L, const char* key, int val) { // 设置table中的key跟val lua_pushstring(L, key); lua_pushnumber(L, (double)val/MAX_COLOR); lua_settable(L, -3);// 设置进table之后,栈顶的两个值会被弹出 } void setcolor(lua_State* L, struct ColorTable* ct) { printf("%d", lua_gettop(L)); lua_newtable(L); // 压入栈顶,从gettop的个数可以看出 printf("%d", lua_gettop(L)); setfield(L, "r", ct->red); setfield(L, "g", ct->green); setfield(L, "b", ct->blue); lua_setglobal(L, ct->name); // 必须最后设置,因为该操作为:出栈弹出table,并设置table名字;即将table为name设置为lua中的global printf("%d", lua_gettop(L)); }
五、调用lua中的函数
func.txt
function f(x, y) return (x^2 * math.sin(y)) / (1-x) end
C代码
void LoadFunc(lua_State* L) { if (luaL_loadfile(L, "func.txt") || lua_pcall(L, 0, 0, 0)) error(L, "load func.txt error"); } double f(lua_State* L, double x, double y) { double z; lua_getglobal(L, "f"); // 将lua全局的名字为f的压入栈 lua_pushnumber(L, x); // 依次将x跟y压入栈中 lua_pushnumber(L, y); if (lua_pcall(L, 2, 1, 0) != 0) //2是指两个参数,1是指要获取1个返回值;如果有n个,则可以设置为n;假设返回值为a,b,c;他们对应的栈为-3,-2,-1 error(L, "error 'f' %s", lua_tostring(L, -1)); //pcall 的最后一个参数如果不为0,则当发生错误时候会调用栈中对应的参数值 if (!lua_isnumber(L, -1)) error(L, "func f must return anumber"); z = lua_tonumber(L, -1); lua_pop(L, 1); return z; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!