Lua调用自定义C模块_Lua

这是《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))

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索lua调用c函数
lua 自定义模块、python调用自定义模块、c 调用lua、lua 调用c 函数、cocos2dx c 调用lua,以便于您获取更多的相关知识。

时间: 2024-09-13 10:46:14

Lua调用自定义C模块_Lua的相关文章

Lua极简入门指南(六):模块_Lua

从用户的角度来看,一个模块能够通过 require 加载并返回一个 table,模块导出的接口都被定义在此 table 中(此 table 被作为一个 namespace).所有的标准库都是模块.标准库被预先加载了,就像这样: 复制代码 代码如下: math = require 'math' string = require 'string' require 函数 使用 require 函数加载模块能够避免多次重复加载模块.加载一个模块: 复制代码 代码如下: require 'modulena

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

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

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

到这为止,大家对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 )

【COCOS2DX-LUA 脚本开发之十四】解决自定义CPP类通过TOLUA++ BINDING LUACOCOS2D后编译到ANDROID运行黑屏(没有调用自定义CPP类)的问题!

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/lua-game/1388.html 唉,首先说点闲话 – -.Himi搞了不短的时间,这个问题一直没有解决,最后终于在张大(cocos2dx引擎开发者之一 张小明)的指导下解决了此问题. 本章基于上一篇  [COCOS2DX-LUA 脚本开发之十三]  与之前的项目整合 [Cocos2d-X(2.x) 游戏开发系列之二]cocos2dx最新

DotNetNuke自定义窗体模块的数据结构(三)

在接触国外的CMS等Open Source产品之前,老实说,我写过的存储过程,包括SQL Server的.Oracle的,加起来绝对不会超过5个,而且还基本上都是从网上抄袭的,主要是觉得太麻烦:嗯,是的,如果数据库设计的不够好,经常需要改动,比如加一个字段,修改一下字段类型的话,需要从数据表.存储过程.调用等一路改上来,确实是挺麻烦的.不过习惯了之后,发现用存储过程确实有它的好处,也被迫养成了对数据库设计要每个字段都斟酌半天的习惯,所以,我们看到DotNetNuke有近乎上千个存储过程(安装了所

dedecms首页调用自定义字段的方法

风信网(ithov.com)原创文章:今天在研究dedecms关于自定义字段的使用,由于首页模块index_article.htm文件中需要调用自定义的字段中的数据.在获取附加表内容时,必须符合以下两个条件: 1.指定 channelid 属性 2.指定要获得的字段 addfields='字段1,字段'&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; 注意:每个字段用英文半角逗号分开如下示例所示: {dede:ch

动易首页调用自定义字段内容的修改方法

动易系统提供了强大的自定义列表标签([ArticleList(参数列表)]列表内容[/ArticleList]),可以让我们更自由更个性的设计自己的页面. 同时,提供的自定义自段更给我们带来了强大的扩展空间. 今天有朋友问题到我在首页调用自定义列表标签时无法解析自定义字段,在页面中直接显示字段名称了. 我以前很少用到自字义字段,而且在首页用自定义列表去调用自字义字段就更没用过了呵. 临时测试一下,果然是这样的.便作了一下修改,让能在首页解析出来.下面说说修改方法: 以文章模块为例,修改Inclu

lua编程 全局变量 环境 模块

1.全局变量与环境 lua中真正存储全局变量的地方不是在_G里面,而是在setfenv(i,table)的table中,所有当前的全局变量都在这里面找,只不过在程序开始时lua会默认先设置一个变量 _G=这个里面的table而已.所以在新设置环境后,如果还想找到之前的全局变量,通常需要附加上为新的table设置元表{_index=_G} 下面的几个例子: a=1 print(a) print(_G.a) --正常情况,输出1,1 a=1 setfenv(1,{}) print(a) print(

lua与C(二):LUA调用c

在lua中调用C函数    c中的函数应该这样准备  注册单个函数:   所有可被lua调用的函数型为 typedef int (*lua_Cfunction)(lua_State*L)   例如 其中返回值是其压入栈的函数返回值的数量 2.然后将函数置入栈中 lua_pushfunction() 3.将函数从栈中推给lua  lua_setglobal(L,name) name是在lua中这个函数的名字   注册一些函数,组成一个模块 1.首先定义这些函数 static int l_dir(l