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代码却有更多的*;更明确的来讲,你可以查询栈上的任何元素,甚至是在任何一个位置插入和删除元素。
C API遵循C语言的语法形式,这Lua有所不同。当使用C进行程序设计的时候,我们必须注意,类型检查,错误处理,内存分配都很多问题。API中的大部分函数并不检查他们参数的正确性;你需要在调用函数之前负责确保参数是有效的。如果你传递了错误的参数,可能得到 \"segmentation fault\" 这样或者类似的错误信息,而没有很明确的错误信息可以获得。另外,API重点放在了灵活性和简洁性方面,有时候以牺牲方便实用为代价的。一般的任务可能需要涉及很多个API调用,这可能令人烦恼,但是他给你提供了对细节的全部控制的能力,比如错误处理,缓冲大小,和类似的问题。如本章的标题所示,这一章的目标是对当你从C调用Lua时将涉及到哪些内容的预览。如果不能理解某些细节不要着急,后面我们会一一详细介绍。不过,在Lua参考手册中有对指定函数的详细描述。另外,在Lua发布版中你可以看到API的应用的例子,Lua独立的解释器(lua.c)提供了应用代码的例子,而标准库(lmathlib.c、lstrlib.c等等)提供了程序库代码的例子。
从现在开始,你戴上了C程序员的帽子,当我们谈到“你/你们”,我们意思是指当你使用C编程的时候。在C和Lua之间通信关键内容在于一个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。栈的使用解决了C和Lua之间两个不协调的问题:第一,Lua会自动进行垃圾收集,而C要求显示的分配存储单元,两者引起的矛盾。第二,Lua中的动态类型和C中的静态类型不一致引起的混乱。我们将在24.2节详细地介绍栈的相关内容。