将Lua加入到C++项目:
方法有2个,第一个就是直接把lua的src源代码直接加入到项目里,方便,快捷。
方案二就是把lua编译成lib库,然后其他项目链接进来,就是了。
方案一:拷贝代码
直接把D:\soft_framework_utiles\lua\lua-5.2.3\src下面的代码拷贝到自己项目里面(除了lua.c和luac.c),
比如:D:\WorkspacesForAll\Lua_C++\Lua_CPP\Lua_CPP\lua
但是要删除lua.c和luac.c这两个文件,因为这两个不是库文件,而是lua执行器和编译器的源文件。
用来编译成两个exe的,不是我们的lib文件。
然后写一个Main方法:
#include <stdlib.h>
// 简单点,直接把lua的src拷贝到我们项目里面
// 然后把lua.c和luac.c移除就可以了
#include "lua/lua.hpp"
int main(int argc, char* argv[])
{
char buff[256];
int errorCode;
// 有的 lua_open是个宏了
// l现在是lua_newstate, luaL_newstate
//
// L = luaL_newstate();//创建一个指向Lua解释器的指针。
// 函数加载Lua库
// 使用 lua_newstate() 创建一个新的 Lua 状态机。
lua_State* luaState = luaL_newstate();
// 若有必要,调用 luaL_openlibs() 函数加载 Lua 的标准库。
luaL_openlibs(luaState);
//一旦初始化了 Lua 脚本引擎,你可以通过如下步骤执行一段 Lua 脚本:
//1. 使用 luaL_loadfile 加载一段 Lua 程序或脚本到 Lua 执行引擎中;
//2. 调用 lua_pcall 函数执行已加载的脚本。
}
方案二:
建立一个空的静态库工程 (最好不使用预编译头,把预编译头的选项勾去掉),然后把src下的所有文件(除了Makefile)一股脑拷到工程中去。然后将这些文件添加到你的工程中,编译,会生成一个*.llib(*是你起的lua库名),行了,建立一个目录lib,把它拷过去,然后再建立一个include的文件夹,把你工程目录下的lua.h,lualib.h,lauxlib.h,拷贝过去。行了,拿着这两个文件夹,你就可以在你的工程里使用lua了。
讲解lua的栈
栈是lua相当重要的一块,肩负着数据的传递,才开始用很可能摸不清方向,但是用熟练了,就会发现那是相当的简单。
栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用
无论你何时想要从Lua请求一个值(比如一个全局变量的值),调用Lua,被请求的值将会被压入栈。
比如:
下面的调用就会取出2个数据放在栈上面:
无论你何时想要传递一个值给Lua,首先将这个值压入栈,然后调用Lua(这个值将被弹出)。
记住:调用lua函数之前,如果他是需要参数的,我们应该先把参数入栈,这样调用才会有参数可取。
不管是调用lua的函数,还是给lua某个字段设置值,都是先把值push入栈
比如给lua的table的某个字段赋值:
// 代码A,就是相当于 myTable .hp = 211
lua_getglobal( L, "myTable" ); // 获取要设置值的table
lua_pushstring( L, "hp" ); // "hp"在栈上的位置为-1
lua_pushnumber( L, 211 ); // "hp"在栈上的位置变为-2,而211则是-1
lua_settable( L, -3 ); // 值被正确的设置到全局变量(表)的myTable中
比如给某个全局变量赋值:
lua_pushnumber( L, 211 );
lua_setglobal( L, "hp" );
lua头文件对栈的描述:
我们要给lua数据,就直接push,然后调用lua接口,要想load数据就直接lua_get**从lua获取数据到栈。
要想知道这数据的值,我们就直接lua_to***(比如lua_tostring)就得到他的值了。
C++中调用某个Lua文件中的函数:
代码如下:FILE_LUA 下面的注释就是这个lua文件的内容。
void TestCPPCallLua::testCallLuaFunction()
{
#define FILE_LUA "scripts/lua002_function.lua"
/***
print("lua002_function.lua");
-- 测试加法和减法
-- 注意这里不是local的
-- 当被load进来的时候相当于返回一个大函数,函数里面有一个全局函数testAdd_Sub
-- 但是这并不代表定义过了testAdd_Sub,只有外面的这个大函数执行以下,这个testAdd_Sub
-- 才会被定义到全局里面
function testAdd_Sub(a,b)
return a+b,a-b
end
*/
//读入的东西当成一个匿名函数放在栈顶上
//这样,这个lua文件就被当做一个匿名函数放在栈顶
//于是可以使用它的数据了。
//跟直接在lua里面loadfile一样,只是加载,并没有定义里面的函数,
//需要执行下才定义里面的testAdd_Sub
int ret = luaL_loadfile(g_State,FILE_LUA);
if (ret != 0)
{
printf("Error :%s --> luaL_loadfile[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
return;
}
// 这里就是lua的一个匿名类,就是那个“大函数”
LuaUtiles::stackDump(g_State);
// 调用testAdd_Sub
// 1.先取得这个函数,要定义了才取得到,所以先运行一下
// 2.取函数
/*1.执行一次,用于定义*/
int runOk = lua_pcall(g_State,0,0,NULL);
if (runOk != 0)
{
printf("Error :%s --> lua_pcall[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
return;
}
// 这里就是空了,因为匿名函数也调用了,就pop出去了
LuaUtiles::stackDump(g_State);
/*2.取函数,就可以取得到函数了,就取到了大函数执行时定义的函数testAdd_Sub*/
lua_getglobal(g_State,"testAdd_Sub");
lua_pushnumber(g_State,10);
lua_pushnumber(g_State,5);
LuaUtiles::stackDump(g_State); // 就输出3个字段
// 2个参数,2个返回值
runOk = lua_pcall(g_State,2,2,NULL);
if (runOk != 0)
{
printf("Error :%s --> lua_pcall[%s] error:[%s]",__FUNCTION__,FILE_LUA,lua_tostring(g_State,-1));
return;
}
// 先返回的是add,后sub,于是sub在-1
printf("testAdd_Sub(10,5) = %d,%d \n",lua_tointeger(g_State,-2),lua_tointeger(g_State,-1));
LuaUtiles::stackDump(g_State); // 还剩下2个返回值
}
测试结果: