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++交互总结(很详细),个人比较懒,不再赘述。

这里面第三种方法比较常用,但是涉及到其他知识。所以我整理了一下相关的资料:

1.[转]静态链接与动态链接的区别

2.VS2012 创建和使用DLL

3.Lua的require使用

这里面有一个坑,那就是如果不想将DLL文件复制到脚本目录下,而采用绝对路径链接的时候,修改的应该是package.cpath=“.../xx.dll”,而不是path,如果修改的是path是无法正确读取动态链接库的。

比如

package.cpath="C:/Users/Documents/visual studio 2013/Projects/mylib/Debug/?.dll"
require "mylib"

 

posted @ 2017-08-28 16:20  Initial_Dream  阅读(300)  评论(0编辑  收藏  举报