Lua学习笔记-C API
学习Lua的最终目的就是为了和C/C++互调,所以C API是承上启下的重头戏。
核心思想:Lua与C通过一个抽象的栈进行通信。你可以理解为Lua和C各司其职,只是通过栈进行沟通,类似操作系统的进程通讯一样。这样做至少有两点好处:1. 程序员不必关心另一个语言是如何工作的,只需要清楚有哪些值是自己需要的 2. 避免类型不一致或者动态内存管理带来的问题,因为C需要手动管理内存,而Lua有自动垃圾回收机制。
关于栈需要了解下面两点:
1. 栈中的严格遵循FIFO,栈底索引为1,栈顶索引为栈中元素个数。另外负数表示从栈顶开始索引,通常用-1方便的获取栈顶元素。
2. Lua的所有C API都是针对栈顶元素进行操作,这里不是说不能修改栈中的值,而是所有的值只能从栈中获取。每次操作可能是获取/修改值,也可能弹出栈顶元素或者压入元素,具体可以参考官方文档。英文不好的也可以参考一下这篇博客Lua5.3——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+b 10 end 11 12 function printTable(t) 13 for i,v in pairs(t) do 14 print(i,v) 15 end 16 end
这里声明了Lua中常用的几种值类型,number,string,boolean,table,function,目的是C代码中对这些值进行操作,能比较全面的了解一下。
下面是调用lua的C文件,不明白extern的作用可以参考这篇extern关键词的作用
1 #include <stdio.h> 2 #include <string.h> 3 #include<iostream> 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 #endif 11 12 extern "C" 13 { 14 #include <lua.h> 15 #include <lauxlib.h> 16 #include <lualib.h> 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); //运行栈中的chunk 33 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元素,所有值均可转为string 42 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
参考了一下网上的方案,发现一篇写的很详细的博客Lua和C++交互总结(很详细),个人比较懒,不再赘述。
这里面第三种方法比较常用,但是涉及到其他知识。所以我整理了一下相关的资料:
这里面有一个坑,那就是如果不想将DLL文件复制到脚本目录下,而采用绝对路径链接的时候,修改的应该是package.cpath=“.../xx.dll”,而不是path,如果修改的是path是无法正确读取动态链接库的。
比如
package.cpath="C:/Users/Documents/visual studio 2013/Projects/mylib/Debug/?.dll" require "mylib"