Lua与C++交互初探之Lua调用C++

转自:http://www.cnblogs.com/Zackzhang/p/5094942.html


上一篇我们已经成功将Lua的运行环境搭建了起来,也成功在C++里调用了Lua函数。今天我来讲解一下如何在Lua里调用C++函数。

Lua作为一个轻量级脚本语言,他只包含了一些必要的系统库函数,当有需要时还得自己去写。有一次我要做一个两数异或的操作发现函数库里居然没有异或运算。不得不非常苦逼的自己去写。后来接触Lua深了之后才知道将这种"缺陷"可以由C函数来弥补。但要做到这一点对于一个对C只知道if else的学生来说确实还是有不少难度。

在学习调用的时候我也确实遇到了不少问题。一开始当然是看不懂代码,各种指针以及莫名其妙的函数,各种头大啊有木有。后来试着静下心来慢慢理了一下Hello World程序,觉得是一知半解了就把代码拷到编译器里运行一下。是的,各种报错。错得我都没信心再看下去了。

好了,上面都是一些没用的,现在开始步入正题。

 

Lua调用C++有两种方法:

  1. 将C函数作为应用程序的一部分
  2. 将C函数作为Lua的一个模块

这里解释一下,将C函数作为程序的一部分,就是说源文件有main方法,函数在main方法里注册,使得c函数成为Lua里的全局函数,供lua直接调用;将C函数作为Lua的一个模块。本人比较喜欢这种方式。其实是将C函数注册后封装到一个模块中,在windows系统中以dll的文件形式存在。在使用时我们只需要将他require进来就行了,另外dll文件也非常方便复制和转移,也保护了源码。所以下面将主要讲解如何将C函数注册成为Lua的模块库。记住:我之所以说是C函数,是因为函数必须以C的形式导出,因此在C++里在函数名前必须加"extern "C"";这一点下面你将会看到

下面来讲讲步骤:

 

  1. 在VS里新建一个VC++的win32项目(控制台应用亦可)
  2. 点击下一步选择dll(以前我们为了省事直接点了finish,这里我们得改一下后面的设置)
  3. 新建完成后配置好lua在VS里的运行环境,不会的可以看一下我的上一篇文章
  4. 输入下面代码

     

    复制代码
    // Mydll.cpp : 定义 DLL 应用程序的导出函数。
    //
    
    #include "stdafx.h"
    #include <stdio.h>
    #include <string.h>
    #include <lua.hpp>
    #include <lauxlib.h>
    #include <lualib.h>
    
    //待注册的C函数
    //需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
    //定义一个求取平均数的函数
    extern "C" int average(lua_State* L)
    {
        double sum=0;
        int num = lua_gettop(L);//获取参数的个数
        for (int i = 1; i <= num;i++)
            sum+= lua_tonumber(L, i);
        //依次获取所有参数值,相加
        lua_pushnumber(L, sum/num);//将平均数压如栈,供lua获取
        
        return 1;//返回返回值个数,通知lua应该在栈里取几个值作为返回结果
    }
    
    extern "C" int Communicate(lua_State* L)
    {
        const char *name = lua_tostring(L, 1);//获取字符串
        printf("Hello %s\n", name);
        printf("I`m in C,I send a message to you");
        lua_pushstring(L, "This message from C");
        return 1;
    }
    //luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
    //第一个字段为C函数指针。
    //结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
    static luaL_Reg cMethods[] = {
        { "average", average },
        { "Communicate", Communicate },
        { 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_Mydll(lua_State* L)
    {
        const char* libName = "Mydll";
        luaL_register(L, libName, cMethods);
        return 1;
    }
    复制代码

     

     

  5. 点击运行后我们把编译好的dll文件复制到lua解析器能找到的位置(lua文件同目录或者LUA_CPATH指向的路径一般在lua安装目录的clibs目录下)
  6. 下面编写lua测试代码

     

    require "Mydll"  --引入包
    
     --在调用时,必须是package.function
    
    print(Mydll.average(1.0,2.0,3.0,4));
    print(Mydll.Communicate("Zack"));

     

     

  7. 测试运行

     

    不过貌似又出现了新问题,我也是才发现的。看一下Communicate函数打印信息的顺序。"This message from C"这则信息是在最后才存在栈中,应该在最后打印才对,它却被提到了前面

    把Communicate函数提到average函数前面,结果更意外:

 

 

我是一个无聊的人,再来●︿●:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值