Lua调用自定义C模块

这是《Lua程序设计》中提到的,但是想成功执行,对于初学Lua的确没那么简单。这里涉及如何如何生成一个动态链接库so文件;Lua5.2中导出函数从LuaL_register变成了LuaL_newlib。对于具体的细节有待深入。这里的模块名是hello_lib, Lua解释器会根据名字找到对应的模块,而后执行其中的 luaopen_XXX方法。 代码:

#include <math.h>
#include <lua5.2/lua.h>
#include <lua5.2/lauxlib.h>
#include <lua5.2/lualib.h>
static int hello_sin(lua_State *L){
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1;
}
static const struct luaL_Reg hello_lib[] = {
{"hello_sin" , hello_sin},
{NULL, NULL}
};
int luaopen_hello_lib(lua_State *L){
luaL_newlib(L, hello_lib);
//luaL_register(L, "hello_lib",hello_lib); // lua 5.1
return 1;
}

在Lua中调用:

local hello = require "hello_lib"
print(hello.hello_sin(1))

执行过程和结果:

1. C函数作为应用程序的一部分。

#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>

//待Lua调用的C注册函数。
static int add2(lua_State* L)
{
  //检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
  //如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
  double op1 = luaL_checknumber(L,1);
  double op2 = luaL_checknumber(L,2);
  //将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
  lua_pushnumber(L,op1 + op2);
  //返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
  return 1;
}

//另一个待Lua调用的C注册函数。
static int sub2(lua_State* L)
{
  double op1 = luaL_checknumber(L,1);
  double op2 = luaL_checknumber(L,2);
  lua_pushnumber(L,op1 - op2);
  return 1;
}

const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";

int main()
{
  lua_State* L = luaL_newstate();
  luaL_openlibs(L);
  //将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码
  //在调用C函数时使用的全局函数名,第二个参数为实际C函数的指针。
  lua_register(L, "add2", add2);
  lua_register(L, "sub2", sub2);
  //在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
  if (luaL_dostring(L,testfunc))
    printf("Failed to invoke.\n");
  lua_close(L);
  return 0;
}

2. C函数库成为Lua的模块。

将包含C函数的代码生成库文件,如Linux的so,或Windows的DLL,同时拷贝到Lua代码所在的当前目录,或者是LUA_CPATH环境变量所指向的目录,以便于Lua解析器可以正确定位到他们。在我当前的Windows系统中,我将其copy到"C:\Program Files\Lua\5.1\clibs\",这里包含了所有Lua可调用的C库。见如下C语言代码和关键性注释:

 #include <stdio.h>
 #include <string.h>
 #include <lua.hpp>
 #include <lauxlib.h>
 #include <lualib.h>

 //待注册的C函数,该函数的声明形式在上面的例子中已经给出。
 //需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
 //函数代码和上例相同,这里不再赘述。
 extern "C" int add(lua_State* L)
 {
   double op1 = luaL_checknumber(L,1);
   double op2 = luaL_checknumber(L,2);
   lua_pushnumber(L,op1 + op2);
   return 1;
 }

 extern "C" int sub(lua_State* L)
 {
   double op1 = luaL_checknumber(L,1);
   double op2 = luaL_checknumber(L,2);
   lua_pushnumber(L,op1 - op2);
   return 1;
 }

 //luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
 //第一个字段为C函数指针。
 //结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
 static luaL_Reg mylibs[] = {
   {"add", add},
   {"sub", sub},
   {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_mytestlib(lua_State* L)
 {
   const char* libName = "mytestlib";
   luaL_register(L,libName,mylibs);
   return 1;
 }

见如下Lua代码:

require "mytestlib"  --指定包名称

--在调用时,必须是package.function

print(mytestlib.add(1.0,2.0))
print(mytestlib.sub(20.1,19))
(0)

相关推荐

  • Lua与C语言间的交互实例

    Lua 是一门轻巧.灵活.扩展性很强的脚本语言,它可以很容易的嵌入到其他语言(C/C++)中使用,这主要得益于其提供了功能强大的 C API,这让其跟 C/C++ 间的互调成为一件很轻松的事. Lua 调用 C Lua 调用 C 函数,其实就是把 C 函数注册到 Lua 中去,把 C 函数地址传递给 Lua 解释器.这个传递是要遵循一个的协议的,即: 复制代码 代码如下: typedef int (*lua_CFunction)(lua_State* L) Lua 和 C 是通过栈(State)

  • Lua中调用C语言函数实例

    在上一篇文章(C调用lua函数)中,讲述了如何用c语言调用lua函数,通常,A语言能调用B语言,反过来也是成立的.正如Java与c语言之间使用JNI来互调,Lua与C也可以互调. 当lua调用c函数时,使用了和c调用lua中的同一种栈,c函数从栈中得到函数,然后将结果压入栈中.为了区分返回结果和栈中的其他值,每一个函数返回结果的个数. 这里有个重要的概念:这个栈不是全局的结构,每个函数都有自己的私有局部栈.哪怕c函数调用了lua代码,lua代码再次调用该c函数,他们有各自独立的局部栈.第一个参数

  • Lua和C++的通信流程分解

    网上关于Lua的教程似乎还没有泛滥,最近刚好学习在Cocos2d-x使用Lua,当然了,我是写教程狂,我会分享我的学习心得的~ (旁白:我噗~!每次你写东西我就要吐槽,你不累么= =)   这是第一课,先来让Lua和C++认识一下,顺便让它们逛街吃饭牵小手什么的- (旁白:...吹,继续吹) 1. Lua的堆栈和全局表 我们来简单解释一下Lua的堆栈和全局表,堆栈大家应该会比较熟悉,它主要是用来让C++和Lua通信的,是的,它们并不认识对方,只能通过堆栈来沟通,就像写信一样. (旁白:它们不会用

  • Lua教程(二十):Lua调用C函数

    Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性.对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数.对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L).简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数.返回值是整型,表示该C函数

  • C#和lua相互调用的方法教程

    前言 自从ulua在官网上出来后,lua 就被u3d开发人员喜爱.国内有几个高手把lua拿过来 接着进行了封装.很多都是新手转过来.lua语法一看遍知,但是大多数人还是不明白两个语言之间的互相调用是怎么一回事,这也是难点和重点.所以今天想跟大家分享一下这方面的知识,让大家少走弯路吧. Lua是一种很好的扩展性语言,Lua解释器被设计成一个很容易嵌入到宿主程序的库.LuaInterface则用于实现Lua和CLR的混合编程. C与lua交互面临以下几个问题: 1.由于lua里面的数据都是动态加载的

  • Lua和C语言的交互详解

    前言 对于Lua的基础总结总算告一段落了,从这篇博文开始,我们才真正的进入Lua的世界,一个无聊而又有趣的世界.来吧. Lua语言是一种嵌入式语言,它本身的威力有限:当Lua遇见了C,那它就展示了它的强大威力.C和Lua是可以相互调用的.第一种情况是,C语言拥有控制权,Lua是一个库,这种形式中的C代码称为"应用程序代码":第二种情况是,Lua拥有控制权,C语言是一个库,这个时候C代码就是"库代码"."应用程序代码"和"库代码"

  • 简单谈谈lua和c的交互

    介绍 lua和c的亲密接触,靠的是一个虚拟栈.lua通过这个虚拟栈来实现和c之间值的互传.栈上的每一个元素是一个lua值(nil,number,string...). 当lua调用c函数的时候,这个函数会得到一个新的栈,这个栈独立于c函数本身的栈,也独立于lua自己的栈.它里面包含了lua要传给c的所有参数,然后c函数会把返回的结果放入这个栈中返回给调用者. 对于栈的查询操作,如果按照栈的规则,只能拿到栈顶的元素.但这里和常规的栈有一些差异.就是可以用一个索引来指向栈上的任何元素.正数的索引(1

  • Lua中调用C++函数实例

    到这为止,大家对Lua和C++之间的通信应该有些熟悉了,今天我们来介绍最后一个操作. (旁白:什么?最后一个?要结束了么?太好了~!) 上一章传送门:http://www.jb51.net/article/55097.htm 1. Lua调用C++的函数 Lua要调用C++的函数还是蛮方便的,首先,我们来创建一个c++函数先: 复制代码 代码如下: public: static int getNumber(int num); int HelloLua::getNumber( int num )

  • C++中调用Lua函数实例

    唉,今天心情有点糟糕,我就少说一些啰嗦的话了. (旁白:太好了-) 上一章传送门:http://www.jb51.net/article/55096.htm 经过前面几章的介绍,相信大家对Lua的堆栈已经比较熟悉了,如果还不是很熟悉的朋友,建议多看几遍前面的教程,或者多敲几次代码. 那么,如果已经对Lua的堆栈比较熟悉,接下来的内容就很简单了. 今天我们来看看C++如何调用Lua的函数,先看看现在Lua文件是什么样的: 复制代码 代码如下: -- helloLua.lua文件 myName =

  • Lua调用自定义C模块

    这是<Lua程序设计>中提到的,但是想成功执行,对于初学Lua的确没那么简单.这里涉及如何如何生成一个动态链接库so文件:Lua5.2中导出函数从LuaL_register变成了LuaL_newlib.对于具体的细节有待深入.这里的模块名是hello_lib, Lua解释器会根据名字找到对应的模块,而后执行其中的 luaopen_XXX方法. 代码: #include <math.h> #include <lua5.2/lua.h> #include <lua5.

  • C#自定义HttpFilter模块完善实例

    本文实例讲述了C#自定义HttpFilter模块完善的方法,分享给大家供大家参考.具体实现方法如下: 一.背景 近期由于要针对项目做用户操作日志,但不想在每个方法里去增加代码,写入用户日志.因为这样具体的方法违背职责单一的原则,若后期日志内容格式发生变更,或其他什么需求,该方法代码主要一变在变,故使用HttpModule模块来完成此功能,感兴趣的朋友可以参考:关于HttpHandler与HttpModule的理解和应用方法 经过实际运用与完善,现在可以再次总结下. 二.拦截时机 现在的版本中,拦

  • Python 跨.py文件调用自定义函数说明

    0 前言 os.chdir() :用于改变当前python工作的目录到指定的路径 sys.path:是python搜索模块的一个路径集,为list,自定义的包可以把存放路径加进去,之后直接调用包名就行了. 1 同一文件夹 一般当前的工作路径是在搜索路径里面,所以不用sys.path.append,如果调用包的时候报错,先使用sys.path查看当前路径在不在list里,不在list里加进去才能直接调用自定义包. 一个文件夹内有两个 .py 文件: exe101.py FileWriteAbout

  • 浅析PHP中call user func()函数及如何使用call user func调用自定义函数

    UCenter源代码里有一个函数call_user_func,开始以为是自己定义的函数,结果到处都找不到.后来才知道call_user_func是PHP的内置函数,该函数允许用户调用直接写的函数并传入一定的参数,下面总结下这个函数的使用方法. call_user_func函数类似于一种特别的调用函数的方法,使用方法如下: <?php function nowamagic($a,$b) { echo $a; echo $b; } call_user_func('nowamagic', "&q

  • js实现屏蔽默认快捷键调用自定义事件示例

    具体如何屏蔽更多的快捷键可以自行google搜索. 这里要说的是如何屏蔽后去执行自定义的事件. 这里为了方便使用的Kibo做例子,使用google搜索出来的结果一般都是javascript原生实现,很简单的,这里不做介绍. 这里是实现了在一个textarea中enter进行保存的例子,屏蔽掉了原来的回车事件. 代码如下: 复制代码 代码如下: //键盘监听 var areaKey = new Kibo($("#aac010")[0]); areaKey.down('enter',doS

  • JS仿iGoogle自定义首页模块拖拽特效的方法

    本文实例讲述了JS仿iGoogle自定义首页模块拖拽特效的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999

  • python调用自定义函数的实例操作

    在python中,想要调用自定义函数必须先声明,然后才能调用.使用函数时,只要按照函数定义的形式,向函数传递必需的参数,就可以调用函数完成相应的功能或者获得函数返回的处理结果. (1)声明函数 python中使用 def 可以声明一个函数,完整的函数是由函数名.参数以及函数实现语句(函数体)组成的. 在函数声明中,也要使用缩进以表示语句属于函数体. 如果函数有返回值,需要在函数中使用return语句返回计算结果,声明函数的一般形式如下: def <函数名>(参数列表): <函数语句>

  • 微信小程序页面调用自定义组件内的事件详解

    这篇文章主要介绍了微信小程序页面调用自定义组件内的事件详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 page page.json { "usingComponents": { "my-component": "../components/component/component", } } page.wxml <my-component id="myComponent&quo

  • Unity之Luaframework框架lua调用C#方法

    前言 最近,新来的同事写接口,需要知道lua怎么调用C#脚本,趁这个机会也给大家分享一下.道理我也不多少,直接上干货. 框架介绍 本项目采用luaframework+ugui,详情咨询度娘. 框架: 创建C#类 首先写个C#脚本,这个脚本里的方法是我们需要在lua中调用的,这里需要调用的方法命名为ShirlnDebug using System.Collections; using System.Collections.Generic; using UnityEngine; public cla

随机推荐