学习Lua的最终目的就是为了和C/C++互调,所以C API是承上启下的重头戏。
核心思想:Lua与C通过一个抽象的栈进行通信。你可以理解为Lua和C各司其职,只是通过栈进行沟通,类似操作系统的进程通讯一样。这样做至少有两点好处:1. 程序员不必关心另一个语言是如何工作的,只需要清楚有哪些值是自己需要的 2. 避免类型不一致或者动态内存管理带来的问题,因为C需要手动管理内存,而Lua有自动垃圾回收机制。
关于栈需要了解下面两点:
1. 栈中的严格遵循FIFO,栈底索引为1,栈顶索引为栈中元素个数。另外负数表示从栈顶开始索引,通常用-1方便的获取栈顶元素。
2. Lua的所有C API都是针对栈顶元素进行操作,这里不是说不能修改栈中的值,而是所有的值只能从栈中获取。每次操作可能是获取/修改值,也可能弹出栈顶元素或者压入元素,具体可以参考。英文不好的也可以参考一下这篇博客,虽然排版有点混乱。
C调用Lua
关于Lua的C API,网上有很多教程,官方文档也很详细,这里不再记录。直入主题,在具体例子中解释。
首先编写一个简单的lua脚本文件t.lua。内容如下
1 int=1 2 double=1.23456 3 s='string' 4 bool=true 5 table={ 1,2,3,n=4} 6 7 function add(a,b) 8 print("a="..a,"b="..b) 9 return a+b10 end11 12 function printTable(t)13 for i,v in pairs(t) do14 print(i,v)15 end16 end
这里声明了Lua中常用的几种值类型,number,string,boolean,table,function,目的是C代码中对这些值进行操作,能比较全面的了解一下。
下面是调用lua的C文件,不明白extern的作用可以参考这篇
1 #include2 #include 3 #include 4 using namespace std; 5 6 //引用lua库 7 #ifdef _DEBUG 8 #pragma comment(lib,"D:\\lua\\luaforwindows-master\\files\\lib\\lua51.lib") 9 #pragma comment(lib,"D:\\lua\\luaforwindows-master\\files\\lib\\lua5.1.lib")10 #endif11 12 extern "C"13 {14 #include 15 #include 16 #include 17 }18 19 int errorMsg(int error); //打印错误信息20 21 lua_State *L = lua_open(); /* opens Lua */22 23 int main(void)24 {25 int error;26 luaL_openlibs(L);27 28 error = luaL_loadfile(L, "E:/lua project/t.lua"); //载入lua脚本作为chunk入栈,但不运行29 if (errorMsg(error))30 return 0;31 32 error = lua_pcall(L, 0, 0, 0); //运行栈中的chunk33 if (errorMsg(error))34 return 0;35 36 lua_getglobal(L, "int"); //找到t.lua中的全局变量int压入栈中,下面类似37 lua_getglobal(L, "double");38 lua_getglobal(L, "s");39 lua_getglobal(L, "bool");40 41 for (int i = 1; i < lua_gettop(L); i++) //打印栈中除table元素,所有值均可转为string42 cout << lua_tostring(L, i) << endl;43 44 lua_getglobal(L, "printTable"); //找到printTable函数入栈45 lua_getglobal(L, "table"); //将参数table入栈46 error = lua_pcall(L, 1, 0, 0); //调用printTable函数47 if (errorMsg(error))48 return 0;49 50 lua_getglobal(L, "add"); //找到add函数入栈51 lua_pushnumber(L, 10); //压入第一个参数52 lua_pushnumber(L, 20); //压入第二个参数53 error = lua_pcall(L, 2, 1, 0); //调用add函数54 if (errorMsg(error))55 return 0;56 57 cout << "result=" << lua_tostring(L, -1); //打印返回值58 59 return 0;60 }61 62 int errorMsg(int error)63 {64 if (error)65 {66 const char *pErrorMsg = lua_tostring(L, -1);67 cout << pErrorMsg << endl;68 return 1;69 }70 return 0;71 }
Lua调用C
参考了一下网上的方案,发现一篇写的很详细的博客,个人比较懒,不再赘述。
这里面第三种方法比较常用,但是涉及到其他知识。所以我整理了一下相关的资料:
1.
2.
3.
这里面有一个坑,那就是如果不想将DLL文件复制到脚本目录下,而采用绝对路径链接的时候,修改的应该是package.cpath=“.../xx.dll”,而不是path,如果修改的是path是无法正确读取动态链接库的。
比如
package.cpath="C:/Users/Documents/visual studio 2013/Projects/mylib/Debug/?.dll"require "mylib"