Lua教程(四):在Lua中调用C语言、C++的函数_Lua

本教程将介绍如何在Lua里面调用c/c++函数。

在Lua里面调用c/c++函数其实是比较简单,本文将通过两个示例演示具体的做法:一个是求平均数,另一个是打印lua函数的一些参数信息。

最后,本文会介绍如何把这两个函数定义成一个模块,这样lua代码里面就可以不再使用全局的名字空间了。

前言

当我们需要在Lua里面调用c/c++函数时,所有的函数都必须满足以下函数签名:

复制代码 代码如下:

typedef int (*lua_CFunction) (lua_State *L);

换句话说,所有的函数必须接收一个lua_State作为参数,同时返回一个整数值。因为这个函数使用Lua栈作为参数,所以它可以从栈里面读取任意数量和任意类型的参数。而这个函数的返回值则表示函数返回时有多少返回值被压入Lua栈。(因为Lua的函数是可以返回多个值的)

示例一

定义C++函数指针

复制代码 代码如下:

int average(lua_State *L)
{
    // get number of arguments
    int n = lua_gettop(L);
    double sum = 0;
    int i;
    // loop through each argument
    for (i = 1; i <= n; i++)
    {
        // total the arguments
        sum += lua_tonumber(L, i);
    }
    // push the average
    lua_pushnumber(L, sum / n);
    // push the sum
    lua_pushnumber(L, sum);
    // return the number of results
    return 2;
}

注册此函数给Lua

复制代码 代码如下:

lua_register(L, "average", average);

Lua里面调用此函数

复制代码 代码如下:

avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)

示例二

定义C++函数

复制代码 代码如下:

int displayLuaFunction(lua_State *l)
{
    // number of input arguments
    int argc = lua_gettop(l);
    // print input arguments
    std::cout << "[C++] Function called from Lua with " << argc
              << " input arguments" << std::endl;
    for(int i=0; i<argc; i++)
    {
        std::cout << " input argument #" << argc-i << ": "
                  << lua_tostring(l, lua_gettop(l)) << std::endl;
        lua_pop(l, 1);
    }
    // push to the stack the multiple return values
    std::cout << "[C++] Returning some values" << std::endl;
    lua_pushnumber(l, 12);
    lua_pushstring(l, "See you space cowboy");
    // number of return values
    return 2;
}

注册此Lua函数

复制代码 代码如下:

 // push the C++ function to be called from Lua
    std::cout << "[C++] Pushing the C++ function" << std::endl;
    lua_pushcfunction(L, displayLuaFunction);
    lua_setglobal(L, "displayLuaFunction");

注意,上一个示例,我们使用的是函数是

复制代码 代码如下:

lua_register(L, "average", average);

它其实只是一个宏定义,其实现也是上面两个函数组成的。

在Lua里调用此函数

复制代码 代码如下:

io.write('[Lua] Calling the C functionn')
a,b = displayLuaFunction(12, 3.141592, 'hola')
-- print the return values
io.write('[Lua] The C function returned <' .. a .. '> and <' .. b .. '>\n')

实现一个Lua模块

首先,我们把这两个C函数封装到一个数组里面:

复制代码 代码如下:

static const luaL_Reg mylibs[]=
{
    {"average", average},
    {"displayLuaFunction", displayLuaFunction},
    {NULL, NULL}
};

接下来,我们定义另一个C函数,让它注册我们的Lua模块:

复制代码 代码如下:

int lua_openmylib(lua_State *L)
{
    luaL_newlib(L, mylibs);
    return 1;
};

这里的luaL_newlib会生成一个table,并把所有的mylibs里面的函数填充进去。最后,lua_openmylib返回值为1,表示会把刚刚生成的table压入栈。

最后,我们像之前注册Lua的标准库一样,注册我们新的库,并给它起名字为mylib:

复制代码 代码如下:

  static const luaL_Reg lualibs[] =
    {
        {"base", luaopen_base},
        {"io", luaopen_io},
        {"mylib", lua_openmylib},
        {NULL, NULL}
    };

此时,我们在Lua里面调用之前的两个函数就需要带上模块名字前缀了:

复制代码 代码如下:

avg, sum = mylib.average(10, 20, 30, 40, 50)
a,b = mylib.displayLuaFunction(12, 3.141592, 'hola')

结语

注意:这里C函数参数里的Lua栈是私有的,每一个函数都有自己的栈。当一个c/c++函数把返回值压入Lua栈以后,该栈会自动被清空。

时间: 2024-09-01 21:33:07

Lua教程(四):在Lua中调用C语言、C++的函数_Lua的相关文章

微信开放平台 公众号第三方平台开发 教程四 代公众号调用接口的SDK和demo

原文:微信开放平台 公众号第三方平台开发 教程四 代公众号调用接口的SDK和demo 教程导航: 微信开放平台 公众号第三方平台开发 教程一 平台介绍 微信开放平台 公众号第三方平台开发 教程二 创建公众号第三方平台 微信开放平台 公众号第三方平台开发 教程三 一键登录授权给第三方平台  微信开放平台 公众号第三方平台开发 教程四 代公众号调用接口的SDK和demo   前几章中我讲解了微信开发平台提供第三方平台的好处,和使用流程,如果你看了我的文章相信你对开放平台有了初步的了解,但是在实际的开

C#中调用脚本语言遇到的问题(急,请您指教)

问题描述 stringcode="functioneventListen()n"+"SetobjEvents=objWMIService.ExecNotificationQuery_n"+"("SELECT*FROM被我隐去的一个类")n"+"DoWhile(True)n"+"SetobjReceivedEvent=objEvents.NextEventn"+"eventLis

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

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

Lua教程(十): 全局变量和非全局的环境_Lua

Lua将其所有的全局变量保存在一个常规的table中,这个table被称为"环境".它被保存在全局变量_G中. 1. 全局变量声明: Lua中的全局变量不需要声明就可以使用.尽管很方便,但是一旦出现笔误就会造成难以发现的错误.我们可以通过给_G表加元表的方式来保护全局变量的读取和设置,这样就能降低这种笔误问题的发生几率了.见如下示例代码: 复制代码 代码如下: --该table用于存储所有已经声明过的全局变量名 local declaredNames = {} local mt = {

Lua教程(九):元表与元方法详解_Lua

Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表达式a+b.当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该元表中是否存在__add字段,如果有,就调用该字段对应的值.这个值就是所谓的"元方法",这个函数用于计算table的和.  Lua中每个值都有一个元表.table和userdata可以有各自独立的元表,而其它数据类型的值则共享其类型所属的单一元表.缺

Lua教程(十六):系统库(os库)_Lua

Lua为了保证高度的可移植性,因此,它的标准库仅仅提供了非常少的功能,特别是和OS相关的库.但是Lua还提供了一些扩展库,比如Posix库等.对于文件操作而言,该库仅提供了os.rename函数和os.remove函数.1. 日期和时间: 在Lua中,函数time和date提供了所有的日期和时间功能. 如果不带任何参数调用time函数,它将以数字形式返回当前的日期和时间.如果以一个table作为参数,它将返回一个数字,表示该table中所描述的日期和时间.该table的有效字段如下: print

ASP.NET 5系列教程 (四):向视图中添加服务和发布应用到公有云

向视图中添加服务 现在,ASP.NET MVC 6 支持注入类到视图中,和VC类不同的是,对类是公开的.非嵌套或非抽象并没有限制.在这个例子中,我们创建了一个简单的类,用于统计代办事件.已完成事件和平均优先级的服务. 1. 添加命名为Services 的文件夹,在该文件夹下添加名称为 StatisticsService.cs 的类: StatisticsService 类代码设计如下: using System.Linq; using System.Threading.Tasks; using

Linux中使用C语言的fork()函数创建子进程的实例教程_C 语言

一.fork入门知识一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己.   我们来看一个例子: #include <unistd.h> #include &l

【Linux】嵌入式开发,在Linux中使用C语言对Fork函数执行子函数及父函数,命令ps 及 ls 操作

<span style="font-family: Arial, Helvetica, sans-serif;">//fork.c</span> #include "sys/types.h" #include "unistd.h" #include "stdio.h" #include "stdlib.h" int main() { pid_t result; result=fork