Lua与C之间的调用
来源:互联网 发布:腾讯大数据分析平台 编辑:程序博客网 时间:2024/05/20 18:46
Lua与C之间的调用
序
周六听了公司大神讲了Lua和C/C++的绑定以及Lua虚拟机的实现过程。感到受益匪浅,怕自己过几日就忘掉,于是写这篇文章用来记录,也看看自己还能回忆起来多少。
C API
概述
Lua是一种嵌入式语言,即Lua不是一个单独运行的程序,而是可以链接到其他程序的库。Lua解释器使Lua程序可以在不同硬件环境下可以跑起来(x86,arm)
,这个解释器是一个简单的应用程序1,它依靠Lua库实现主要功能。与此同时,一个使用了Lua的程序可以在Lua环境中注册用C语言实现新的函数,由此可以向Lua添加某些Lua无法直接用Lua编写的功能。
以上两种形式,第一种形式中C语言有控制权,Lua是一个库,这种形式C代码是“应用程序代码”;第二种形式中,Lua有控制权,C语言是个库,C是“库代码”。应用程序和库代码都是用同样的API来与Lua通信,这就是C API
Lua和C语言通信主要通过虚拟栈,栈可以解决Lua和C语言之间的两大差异
- Lua使用垃圾收集,而C语言要求显示释放内存
- Lua使用动态类型,而C语言使用静态类型
示例
用C API,实现C调用Lua,执行万能的HelloWorld
VS2010配置
VS2010中的解决方案资源管理器结构如图,先用已有的Lua源代码生成Lua.lib
,TestLua引入该库,就可以调用相应的API方法。
代码实现
extern "C"{#include <lua.h>#include <lualib.h>#include <lauxlib.h>}int _tmain(int argc, _TCHAR* argv[]){ lua_State *L = luaL_newstate(); //打开Lua,创建新的环境 luaL_openlibs(L); //打开所有的标准库 const char *buf = "print('Hello World')"; //Lua代码 luaL_dostring(L,buf); //相当于Lua代码中的dostring lua_close(L); //关闭Lua状态 getc(stdin); return 0;}
执行改代码后在输出窗口会输出Hello World
栈
在Lua中,a[k]=v
表达式里k和v可以是Lua中的任意类型(table,number,string…)。要在C语言中实现上述表达式,因为C是固定参数类型,所以要为每个类型写一个settabel函数。(这里要是用C++实现就可以用动态类型参数实现了…)
上述问题可以用C联合(union)来解决。假设这种类型叫lua_Value,能够表示所有Lua类型。那么settabel声明为:
void lua_settable(lua_Value a, lua_Value k, lua_Value v);
这种做法有两个缺点:
- 很难讲这种复杂的类型映射到其他语言中。Lua本身就要多语言适用(c++,java,c#…)
- Lua的垃圾回收机制。如果该变量在C变量中,Lua引擎认为该table是垃圾文件,回收它。
Lua引擎为了解决上述问题,采取的方法是:
用抽象栈在Lua和C语言之间传递数据,Lua调用C API从栈中弹出数据使用。为了将C类型压入栈,需要为C的每种类型定义一个特定的函数,该方法远小于为了适用不同语言而定义settabel的数量, 也加强了语言的扩展性。另外,这个栈是Lua管理,垃圾收集器能确定C语言使用那些值。
注:Lua严格按LIFO(先出后进)规范来操作这个栈,当调用Lua时,Lua只会该变栈的顶部。C可以任意操作。
压栈
/*** push functions (C -> stack)*/LUA_API void (lua_pushnil) (lua_State *L);LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n);LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l);LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp);LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);LUA_API void (lua_pushboolean) (lua_State *L, int b);LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);LUA_API int (lua_pushthread) (lua_State *L);
以上是每个对应C类型的压入函数。
注:当Lua启动,或Lua调用C语言时,占中至少会有20个空闲的槽2
出栈
出栈是指Lua用C API调用栈中元素。API使用索引来引用栈中的元素。
C中实现Lua的调用代码:
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum);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_rawlen) (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);
为了演示以上函数的调用,以下代码实现了一个打印整个栈的内容的辅助函数:
static 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,i)); break; } } printf(" "); } printf("\n");}
以下代码展示了使用上述代码实现打印的例子:
lua_State *L = luaL_newstate(); //打开Lua,创建新的环境 lua_pushboolean(L,1); lua_pushnumber(L,10); lua_pushnil(L); lua_pushstring(L,"Hello"); stackDump(L);/*ture '10' 'nil' 'hello'*/ lua_close(L); //关闭Lua状态
错误处理
如果发生错误有两种做法:
1. 设置一个“紧急”函数,让它不要把控制权返回给Lua。例如,调用longjmp转到之前setjmp所设置的位置。2. 让代码在“保护模式”下运行。
Lua用的标准的错误处理方法。当一个C函数检测到一个错误时,它就应该调用lua_error。lua_error函数会清理Lua中所有需要清理的东西,然后跳转回发起执行的lua_pcall,并附上错误信息。
- 少于400行代码 ↩
- 这个常量是由LUA_MINSTACK定义的 ↩
- Lua与C之间的调用
- Lua笔记 & 与C之间的交互
- C/C++与Lua的相互调用
- lua与C的互相调用
- Lua 脚本语言 与 C的互相调用
- LUA和C之间的函数相互调用
- lua和C/C++语言之间的调用
- lua与c互调--c调用lua
- lua与c互调--lua调用c
- c和lua之间互相调用方法
- lua study & c与lua相互调用
- Python与C之间的相互调用
- C与C++之间的调用
- lua与lua之间的调用及对表的访问
- c与lua 相互调用
- lua与C相互调用
- Lua编程之Lua和C之间互相调用方式
- 快速掌握Lua 5.3 —— Lua与C之间的交互概览
- MySQL数据库之多表操作
- Jenkins进阶系列之——06FTP publisher plugin插件下载(支持绝对路径)
- Jenkins进阶系列之——07更改Jenkins的主目录
- hdu--1009
- Jenkins进阶系列之——08Jenkins纳入版本控制
- Lua与C之间的调用
- Leetcode 2 - Add Two Numbers
- Jenkins进阶系列之——09配置Linux系统ssh免密码登陆
- 四种会话跟踪技术
- 手游开发中所有特殊的文件夹
- Rendering Statistics Window
- vs2013下debug模式下不能执行断点解决方法
- Jenkins进阶系列之——10Publish Over SSH插件
- Unity3D Lightmap贴图加载替换