书本下载地址 http://download.csdn.net/detail/myy2012/5349646
本部分下载地址 http://download.csdn.net/detail/myy2012/5390585
lua程序设计第二版 读书笔记(1-4章)
第一章 开始
第二章 类型与值
第三章 表达式
第四章 语句
http://blog.csdn.net/myy2012/article/details/8900424
lua程序设计第二版 读书笔记(5-8章)
第五章 函数
第六章 深入函数
第七章 迭代器与泛型for
第八章 编译执行与错误
http://blog.csdn.net/myy2012/article/details/8906466
lua程序设计第二版 读书笔记(9-10章)
第九章 协同程序
第十章 完整的实例
http://blog.csdn.net/myy2012/article/details/8911206
lua程序设计第二版 读书笔记(11-14章)
第十一章 数据结构
第十二章 数据文件与持久性
第十三章 元表metatable与元方法meatmethod
第十四章 环境
http://blog.csdn.net/myy2012/article/details/8914457
lua程序设计第二版 读书笔记(15-17章)
第十五章 模块与包
第十六章 面向对象编程
第十七章 弱引用 table
http://blog.csdn.net/myy2012/article/details/8921632
lua程序设计第二版 读书笔记(18-21章)
第十八章 数学库
第十九章 table库
第二十章 字符串库
第二十一章 IO库
http://blog.csdn.net/myy2012/article/details/8925895
lua程序设计第二版 读书笔记(22-23章)
第二十二章 操作系统库
第二十三章 调试库
http://blog.csdn.net/myy2012/article/details/8930181
要想在C函数中调用Lua代码:
首先在vs中设置lua环境
工具--->选项
24.1 第一个示例
头文件Lua.h中定义了Lua提供的基础函数:包括创建Lua环境,调用Lua函数(如lua_pcall)、读写Lua环境中的全局变量、注册供Lua调用的新函数。
注:lua.h中定义所有内容都有一个lua_前缀。
头文件lauxlib.h定义了辅助库(auxiliary library, auxlib)提供的函数。辅助库并没有直接访问Lua的内部,它都是用官方的基础API来完成所有工作的。
注:lauxlib.h中定义所有内容都有一个luaL_前缀。
头文件lualib.h中定义了打开这些库的函数,而辅助库函数luaL_openlibs则可以打开所有的标准库。
Lua库中没有定义任何全局变量,它将所有的状态都保存在动态结构lua_State中,所有的C API都要求传入一个指向该结构的指针。这种实现使得Lua可以重入(reenter),稍加修改即可用于多线程的代码中。
程序调用luaL_loadbuffer来编译用户输入的每行内容。如果没有错误,返回0,并向栈中压入编译后的程序块。然后,程序调用lua_pcall(将程序块从栈中弹出),并在保护模式中运行它。注:若发生错误,就会向栈中压入一条错误消息,用lua_tostring可以获取这条消息,打印后可以用lua_pop把它从栈中删除。
#ifdef __cplusplus
extern "C"
{
#endif
#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "lua51.lib")
}
int main(void)
{
char buff[256];
int error;
lua_State *L=luaL_newstate();//打开Lua
luaL_openlibs(L);//打开标准库
while (NULL!=fgets(buff, sizeof(buff), stdin))
{
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;
}
24.2 栈
Lua API 中使用了一个抽象的栈,在Lua和C语言之间交换数据。几乎所有的API函数都会用到这个栈。
Lua严格地按LIFO(Last in , First out 先进后出)规范来操作这个栈。当调用Lua时,Lua只会改变栈的顶部,不过C代码有更大的自由度,它可以检索栈中间的元素,甚至在栈的任意位置插入或者删除元素。
在头文件lua.h文件中有如下的定义:
向栈中压入一个元素时,应该确保栈中具有足够的空间(当Lua启动时,或者Lua调用C语言时,栈中至少会有20个空闲的槽)。一般这些空间对于普通的应用是足够了,所有无须顾及空间上的问题。当然也有例外,这时候可以调用lua_checkstack函数来检查栈中是否有足够的空间:
int lua_checkstack( lua_State *L, int sz);
API 使用“索引”来引用栈中的元素:第一个压入栈中的元素索引为1,第二个为2,依次类推知道栈顶。此外,最后压入的元素(栈顶)索引为-1,栈顶下面的元素为-2,依次类推。
为了检查一个元素是否为特定的类型,API提供了一系列的函数lua_is*
在头文件lua.h文件中有如下的定义:
若要检查一个元素是否为真正的字符串或者数字(无须转换的),也可以用以下函数
在头文件lua.h文件中有如下的定义:
除了在C语言和栈之间交换数据的函数外,API还提供了以下这些用于普通栈操作的函数:
说明:
1.lua_gettop函数返回栈中元素的个数(栈顶元素的索引)
2.lua_settop函数将栈顶设置为一个指定的位置(修改栈中元素的数量----多着弃,少则用nil补)。注:lua_settop(L, 0); //清空栈
另外API根据这个函数还提供了一个宏:
3.lua_pushvalue函数会将指定索引上值的副本压入栈。
4.lua_remove函数删除指定索引上的元素,并将该位置之上的所有元素下移以填补空缺
5.lua_insert函数会上移所有元素以开辟一个槽的空间,然后将栈顶元素移到该位置。
6.lua_replace弹出栈顶的值,并将该值设置到指定的索引上,但它不会移动任何东西。
void testStack(lua_State* L)
{
lua_pushboolean(L, 1);//索引为1
lua_pushnumber(L, 10);//索引为2
lua_pushnil(L);//索引为3
lua_pushstring(L, "hello");//索引为4
stackDump(L);
lua_pushvalue(L, 2);//将指定索引()上值的副本压入栈
stackDump(L);
lua_replace(L, 3);//弹出栈顶的值,并将该值设置到指定的索引()上
stackDump(L);
lua_settop(L, 6);//将栈顶设置为一个指定的位置
stackDump(L);
lua_remove(L, -3);//删除指定索引上的元素,并将该位置之上的所有元素下移以填补空缺
stackDump(L);
lua_settop(L, -5);//
stackDump(L);
}
24.3 C API中的错误处理
Lua中所有的结构都是动态的,它们会根据需要来增长或者缩小。在Lua中有许多地方可能会发生内存分配错误,在发生错误时,使用异常来标记这些错误。因此,几乎所有的API函数都会抛出错误(即调用longjmp),而不是返回错误。
当Lua发现了例如“内存不足”这类错误时,它基本不会进行太多的处理,而是调用一个“紧急”函数(Panic Function),当这个函数返回后,Lua就好结束应用程序。(用户通过函数lua_atpanic来设置自己的“紧急”函数)
不是所有的API函数都会抛出异常,像函数luaL_newstate、lua_load、lua_pcall和lua_close都是安全的。
如果发生内存分配错误,其他大多数函数都会抛出异常。例如:luaL_loadfile无法为文件名字符串分配到足够的内存。
函数lua_cpcall类似于lua_pcall,但它接受一个C函数作为参数,然后调用这个C函数(将一个函数)。
第二十五章 扩展应用程序
lua的一项重要用途就是作为一种配置语言(configuration language)
25.1 基础
假设已经创建了一个Lua状态,这个函数调用luaL_loadfile从文件fname加载程序块,然后调用lua_pcall运行编译好的程序块。
void load(lua_State* L, const char* fname, int* w, int* h)
{
if (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0))
{
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L, "width");
lua_getglobal(L, "height");
if (!lua_isnumber(L, -2))
{
printf("'width' should be a number\n" );
return;
}
if (!lua_isnumber(L, -1))
{
printf("'height' should be a number\n" );
return;
}
*w = lua_tointeger(L, -2);
*h = lua_tointeger(L, -1);
}
25.2 table操作
我们可以在C语言的代码中操作Lua中的table数据,这是一个非常方便且非常实用的功能。这样不仅可以使Lua代码的结构更加清晰,也可以在C语言代码中定义等同的结构体与之对应,从而大大提高代码的可读性。
使用table来表示颜色:background={ r=0.30, g=0.10, b=0}
void load2(lua_State* L)
{
if (luaL_loadstring(L, "background = { r = 0.30, g = 0.10, b = 0 }")
|| lua_pcall(L, 0, 0, 0))
{
printf("Error Msg is %s.\n", lua_tostring(L,-1));
return;
}
//*************
lua_getglobal(L, "background");
if (!lua_istable(L, -1))
{
printf("'background' is not a table.\n" );
return;
}
//*************
lua_getfield(L, -1, "r");
if (!lua_isnumber(L, -1))
{
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L, -1) * 255);
lua_pop(L, 1);
//*************
lua_getfield(L, -1, "g");
if (!lua_isnumber(L, -1))
{
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
//*************
lua_pushnumber(L, 0.4);
lua_setfield(L, -2, "b");
lua_getfield(L,-1,"b");
if (!lua_isnumber(L,-1))
{
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
//*************
printf("r = %d, g = %d, b = %d\n", r, g, b);
lua_pop(L, 1);
lua_pop(L, 1);
return;
}
25.3 调用Lua函数
Lua允许在一个配置文件中定义函数,并且还允许应用程序调用这些函数。
调用函数的API协议很简单:首先,将待调用函数压入栈,并压入函数的参数;然后使用lua_pcall进行实际的调用;最后将调用结果从栈中弹出。
void testCallLua(lua_State* L)
{
if (luaL_loadfile(L, filepath))
{
printf("Failed to run lua code.\n");
return;
}
double x = 3.0, y = 4.0;
lua_getglobal(L,"foo");
lua_pushnumber(L, x);
lua_pushnumber(L, y);
if (lua_pcall(L, 2, 1, 0))
{
printf("error is %s.\n",lua_tostring(L,-1));
return;
}
if (!lua_isnumber(L,-1))
{
printf("function 'foo' must return a number.\n");
return;
}
double ret = lua_tonumber(L, -1);
lua_pop(L, -1);
printf("The result of call function is %f.\n", ret);
}
25.4 一个通用的调用函数
call_va 会处理所有的API函数。
函数:call_va ( “f”, “dd>d”, x, y, &z);
说明:“dd>d”表示两个双精度类型的参数和一个双精度类型的参数(d---双精度、i---整数、s---字符串);> 表示参数和结果的分隔符(如果函数没有结果,>是可选的)。
void call_va(lua_State* L, const char* func, const char* sig, ...)
{
va_list vl;
int narg=0, nres=0;//参数和结果的数量
va_start(vl, sig);
lua_getglobal(L, func);//压入函数
//压入参数
for (narg=0; *sig; narg++)
{
//检查栈中空间
luaL_checkstack(L, 1, "too many argument");
switch (*sig++)
{
case 'd'://double参数
lua_pushnumber(L, va_arg(vl, double));
break;
case 'i'://int参数
lua_pushinteger(L, va_arg(vl, int));
break;
case 's'://字符串参数
lua_pushstring(L, va_arg(vl, char*));
break;
case '>'://参数结束
break;
default:
printf("invalid option(%c)", *(sig-1));
}
}
nres=strlen(sig);
if (0 != lua_pcall(L, narg, nres, 0))//完成调用
{
printf("error calling %s:%s", func, lua_tostring(L, -1));
}
//<检索结果>
nres=-nres;//第一个结果的栈索引
while (*sig)
{
switch (*sig)
{
case 'd'://double结果
{
if (!lua_isnumber(L, nres))
printf("wrong result type");
*va_arg(vl, double *) = lua_tonumber(L, nres);
}
break;
case 'i':
{
if (!lua_isnumber(L, nres))
printf("wrong result type");
*va_arg(vl, int *) = (int)lua_tonumber(L, nres);
}
break;
case 's':
{
if (!lua_isstring(L, nres))
printf("wrong result type");
*va_arg(vl, const char **) = lua_tostring(L, nres);
}
break;
default:
printf("invalid option (%c)", *(sig - 1));
}
nres++;
*sig++;
}
va_end(vl);
}
调用函数实例:
int x=5, y=8, z=0;
call_va(L, "add", "ii>i", x, y, &z);
printf("x+y=%d \n", z);
double xx=10.0, yy=15.0, zz=0.0;
call_va(L, "add", "dd>d", xx, yy, &zz);
printf("xx+yy=%f \n", zz);
第二十六章 从lua调用C
当Lua调用C函数时,也使用了一个与C语言调用Lua时相同的栈。C函数从栈中获取函数参数,并将结果压入栈中。为了在栈中将函数结果和其他值区分开,C函数还应返回其压入栈的结果数量。
当Lua调用一个C函数时,第一个参数总是这个局部栈的索引1。
26.1 C函数
所有注册到Lua中的函数都具有相同的原型,该原型就是定义在lua.h中的lua_CFunction: typedef int ( *lua_CFunction ) ( lua_State *L )
说明:从C语言的观点来看,这个C函数仅有一个参数(Lua的状态)。它返回一个整数,表示其压入栈中的返回值数量(因此,这个函数无须在压入结果前清空栈, 在它返回后,Lua会自动删除栈中结果之下的内容)。
在注册(函数lua_pushcfunction)完后,C函数就具有与其他Lua函数一样的行为。
26.2 C模块
Lua模块是一个程序块(chunk),其中定义了一些Lua函数,这些函数通常存储为table的条目。
一旦C函数被注册之后,Lua调用这个函数并不依赖于函数名,包的位置,或者调用函数的可见规则。通常C库都有一个外部(public/extern)的用来打开库的函数。其他的函数可能都是私有的,在C中被声明为static。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
附加:Lua调用C函数实例
代码部分参考于文章 http://www.cnblogs.com/stephen-liu74/archive/2012/07/23/2469902.html
1.首先配置vs为生成dll文件的格式 如下
2.加上代码 生成dll文件
#ifdef __cplusplus
extern "C"
{
#endif
#include
#include
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#pragma comment(lib, "lua51.lib")
}
//extern "C":函数必须以C的形式被导出
extern "C" int add(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
extern "C" int sub(lua_State* L)
{
double op1 = luaL_checknumber(L, 1);
double op2 = luaL_checknumber(L, 2);
lua_pushnumber(L,op1 - op2);
return 1;
}
//luaL_Reg结构体中{字符串,函数名}
//最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
static luaL_Reg mylibs[] = {
{"add", add},
{"sub", sub},
{NULL, NULL}
};
//该C库的唯一入口函数。见如下几点说明:
//1. 我们可以将该函数简单的理解为模块的工厂函数。
//2. 其函数名必须为luaopen_xxx,其中xxx表示library名称。Lua代码require "xxx"需要与之对应。
//3. 在luaL_register的调用中,其第一个字符串参数为模块名"xxx",第二个参数为待注册函数的数组。
//4. 需要强调的是,所有需要用到"xxx"的代码,不论C还是Lua,都必须保持一致,这是Lua的约定,
// 否则将无法调用。
extern "C" __declspec(dllexport)
int luaopen_mytestlib(lua_State* L)
{
const char* libName = "mytestlib";
luaL_register(L, libName, mylibs);
return 1;
}
3.运行后,可以看到debug文件下有test3.dll 文件
拷贝出来和lua文件(这边是26.lua)放在同一个目录下:
4.修改test3.dll文件名为 mytestlib.dll
如下:
5.lua文件中的内容和运行结果如下:
require "mytestlib" --指定包名称
--在调用时,必须是package.function
print(mytestlib.add(1.0,2.0))
print(mytestlib.sub(20.1,19))
本实例参代码部分考于文章
http://www.cnblogs.com/stephen-liu74/archive/2012/07/23/2469902.html