C++ – Lua C API
1. Lua解释器
Lua解释器是什么?
Lua解释器是一个使用Lua标准库实现的独立的解释器,是一个很小的Lua应用(总共不超过500行的代码)。解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给Lua标准库,Lua标准库负责最终的代码运行。
当Lua作为独立程序运行的时候,Lua和Lua解释器打交道。
2. Lua扩展程序
(1) Lua扩展C程序 : C作为应用程序语言,Lua作为一个库使用
(2) C程序扩展Lua : Lua作为程序语言,C作为库使用
在实际应用中,比如游戏开发中日常活动、关卡、战场等主要逻辑基本都是由Lua脚本扩展完成。游戏主程序调用活动脚本,则是Lua扩展了C程序(C程序装载Lua脚本);而在脚本中必须获得一些玩家信息,比如玩家所在地图编号、玩家位置等等,则是C程序开放了API给Lua调用,是C程序扩展了Lua(Lua程序调用C)。
所以扩展的概念是相互的,你提供信息给我,然后我帮你完成工作。当然可以纯粹一方提供另一方服务,还要看实际需要环境。这里只是以游戏中Lua使用为例子说明:C开放API给Lua虚拟机,Lua脚本围绕这些API完成委托的任务,然后C调用Lua脚本完成逻辑。
3. Lua C API
Lua C API是Lua和C通信的一组API,它的功能有这些:
(1)读写Lua全局变量的函数
(2)调用Lua函数的函数
(3)运行Lua代码片断的函数
(4)注册C函数然后可以在Lua中被调用的函数
牺牲健壮性:API中的大部分函数并不检查他们参数的正确性;如果你传递了错误的参数,可能得到"segmentation fault"这样或者类似的错误信息,而没有很明确的错误信息可以获得。
获得灵活性和简洁性
4. 重要头文件和函数说明
(1) lua.h:定义了Lua提供的基础函数,所有在lua.h中被定义的都有一个lua_前缀
创建一个新的Lua环境的函数:lua_open
调用Lua函数的函数:lua_pcall
读取/写入Lua环境的全局变量的函数:
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
int lua_is... (lua_State *L, int index);
int lua_gettop (lua_State *L);
void lua_settop (lua_State *L, int index);
void 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_settop(L, -1); /* set top to its current value */
lua_insert(L, -1); /* move top element to the top */
……
注册可以被Lua代码调用的新函数的函数
(2) lauxlib.h:lauxlib.h定义了辅助库(auxlib)提供的函数,所有在其中定义的函数等都以luaL_打头,辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象;所有Lua标准库都使用了auxlib
5. lua_State结构
Lua库没有定义任何全局变量。它所有的状态保存在动态结构lua_State中,而且指向这个结构的指针作为所有Lua函数的一个参数。这样的实现方式使得Lua能够重入(reentrant)且为在多线程中的使用作好准备。
lua_State可以视为Lua运行环境,是一个封闭的环境。每次lua_open()都获得一个新的Lua运行环境,与之前的环境没有任何交叉因素
6. Lua和C通信的秘密
Lua和c通信的秘密在于:虚拟栈。栈的使用解决了C和Lua之间两个不协调的问题:第一、Lua会自动进行垃圾收集,而C要求显示的分配存储单元,两者引起的矛盾;第二、Lua中的动态类型和C中的静态类型不一致引起的混乱。
栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用,Lua以一个严格的LIFO规则来操作栈。当你调用Lua时,它只会改变栈顶部分。C代码却有更多的自由;更明确的来讲,你可以查询栈上的任何元素,甚至是在任何一个位置插入和删除元素。