[LUA学习笔记03]LUA函数和C函数的相互调用

lua 调用 C Lua调用C函数(lua-5.2.3) 由sf0501创建,小路依依 最后一次修改2016-11-16 Lua可以调用C函数的能力将极大的提高Lua的可扩展性可用性。 对于有些操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数。 对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef in... 阅读详情
 

1. 简介

LUA和C之间的函数调用也是基于上一节提到的栈。

1.1 从C程序调用LUA函数

LUA的函数和普通变量一样也是First Class Variable类型,可以看作函数指针变量参与栈操作。因此调用过程分为如下几个步骤:
  1. 请求LUA函数(指针)入(GLOBAL)栈。
  2. 将函数需要的参数入栈,入栈顺序按照参数被声明的顺序。
  3. 告知LUA虚拟机入栈参数的个数、函数返回值的个数,并调用此LUA函数。
  4. 从栈定获得返回值,先返回的先入栈,然后将返回值显式出栈。

1.2 从LUA脚本调用C函数

LUA没有提供PYTHON那样丰富的类库,因此复杂的功能需要在C程序中定义好,然后通过lua决定调用时机。在LUA库中定义了可以被LUA虚拟机识别的C函数模型:
int functionName (lua_State* L) {....; return 1;}

这样的函数被是一个合法的lua_CFunction类型,将函数注册到LUA虚拟机中以后,就可以在LUA中以普通LUA函数的方式被调用。注册一个C函数的步骤如下:
  1. 声明并定义一个满足上述模型的函数 (eg. myFunInC)
  2. 用字符串为此C函数取一个名称并入栈(eg. myFunInLua)
  3. 将函数(指针)入栈
  4. 调用LUA库的注册函数功能,将上述的名称与函数指针关联
这样就可以在LUA中用myFunInLua()来调用C中的int myFunInC()了

2. 从C调用LUA函数示例

在下面的代码中,我们调用了LUA脚本中的fnEx2函数,返回值从栈中取得,并且要手动出栈。这里,入栈的函数参数会由pcall自动清理。

2.1 LUA测试脚本代码

function fnex2(str_a, num_b, num_c)
    print(str_a);
    return num_b
*100 + num_c*10"Thank you";
end;



2.2 VC代码

//初始化LUA虚拟机
void InitLuaState(lua_State* L)
{
    
/* Load Libraries */
    luaopen_base(L);
    luaopen_table(L);
    luaL_openlibs(L);
    luaopen_string(L);
    luaopen_math(L);
}


int call_lua_function(void)
{
    
const char* szInParam = "This is an [IN] parameter";
    
const int iParam1 = 20, iParam2 = 50;
    cout 
<< "=================================" << endl
         
<< "02_Call_Function" << endl
         
<< "=================================" << endl
         
<< "This demo calls functions in LUA scripts." << endl
         
<< "Argument 1:" << szInParam << endl
         
<< "Argument 2:" << iParam1 << endl
         
<< "Argument 3:" << iParam2 << endl
         
<< "---------------------------------" << endl
         
<< "#OUTPUTS#" << endl;

    lua_State
* L = lua_open();
    InitLuaState(L);

    
int iError;

    
/* Load Script */
    iError 
= luaL_loadfile(L, "../test02.lua");
    
if (iError)
    
{
        cout 
<< "Load script FAILED!" 
             
<< lua_tostring(L, -1)
             
<< endl;
        lua_close(L);
        
return 1;
    }


    
/* Run Script */
    iError 
= lua_pcall(L, 000);
    
if (iError)
    
{
        cout 
<< "pcall FAILED"
             
<< lua_tostring(L, -1)
             
<< iError 
             
<< endl;
        lua_close(L);
        
return 1;
    }

    
    
/* Push a FUNCTION_VAR to STACK */
    lua_getglobal(L, 
"fnex2");

    
/* Push PARAMETERS to STACK */
    lua_pushstring(L, szInParam);
    lua_pushnumber(L, iParam1);
    lua_pushnumber(L, iParam2);

    
/* Call FUNCTION in LUA */
    iError 
= lua_pcall( L,    //VMachine
                        3,    //Argument Count
                        2,    //Return Value Count
                        0 );
    
if (iError)
    
{
        cout 
<< "pcall FAILED"
             
<< lua_tostring(L, -1)
             
<< iError 
             
<< endl;
        lua_close(L);
    }


    
/* Check Return Value Types */
    
if (lua_isstring(L, -1&& lua_isnumber(L, -2))
    
{
        cout 
<< "Ret_1(string): " << lua_tostring(L, -1<< endl;
        cout 
<< "Rec_2(double): " << lua_tonumber(L, -2<< endl;
    }

    
else
    
{
        cout 
<< "Wrong Return Values" << endl;
    }


    
/* POP STACK */
    lua_pop(L,
2);    //只需要清理Return Value,pcall调用的入栈参数会自动清理
    lua_close(L);
    
return 0;
}



2.3 工具

下面的宏可以简化调用lua函数的代码:
#define CallLuaFunc(FuncName, Params, Results) 

    lua_getglobal (g_pLuaState, FuncName); 
    lua_call (g_pLuaState, Params, Results); 
}



3. 从LUA调用C函数示例

在下面的例子中,我们注册一个名为rmath的LUA函数,他在C中的函数名为RMath_LUA()

3.1 LUA脚本代码

print (">>> LUA程序开始运行了 ");

function fnex3(num_a, num_b)
    
local c = rmath(num_a, num_b);
    print(
"LUA PRINTTING:", c);
    return c;
end;



3.2 VC程序代码

//LUA脚本调用C函数
int call_c_function(void)
{
    
int iArg1 = 3, iArg2 = 10, iError;
    cout 
<< "=================================" << endl
         
<< "下面的程序演示从LUA脚本中调用C函数" << endl
         
<< "Argument 1:" << iArg1 << endl
         
<< "Argument 2:" << iArg2 << endl
         
<< "---------------------------------" << endl
         
<< "#OUTPUTS#" << endl;
    lua_State
* L = lua_open();
    InitLuaState(L);

    iError 
= luaL_loadfile(L, "../test03.lua");
    
if (iError) cout << "载入脚本失败" << endl;

    iError 
= lua_pcall(L, 000);
    
if (iError) cout << "执行LUA脚本失败" << endl;

    
/* 将C函数(指针)压栈 */
    lua_pushstring(L, 
"rmath");
    lua_pushcfunction(L, RMath_LUA);
    lua_settable(L, LUA_GLOBALSINDEX);

    
/* LUA函数也是变量(指针),可以压入栈 */
    lua_getglobal(L, 
"fnex3");

    
/* 将提供给LUA函数的参数入栈 */
    lua_pushnumber(L, iArg1);
    lua_pushnumber(L, iArg2);

    
/* 调用LUA函数(pcall函数会自动清除入栈的变量) */
    
int Error = lua_pcall(  L,        //虚拟机指针
                            2,        //2个参数
                            1,        //1个返回值
                            0 );

    
if (Error) cout << "pcall调用fnex3函数失败" << endl;

    
/* 检验返回值类型 */
    
if (lua_isnumber(L, -1))
    
{
        cout 
<< "有1个(double)返回值 = "
             
<< lua_tonumber(L, -1)
             
<< endl;
    }


    
/* 将LUA函数返回值出栈 */
    lua_pop(L, 
1);
    lua_close(L);
    
return 0;
}


//可供LUA调用的C函数原型
int RMath_LUA(lua_State* L)
{
    
if (!lua_isnumber(L, 1))
    
{
        lua_pushstring(L, 
"Arg_1不是数字");
        lua_error(L);
    }


    
if (!lua_isnumber(L, 2))
    
{
        lua_pushstring(L, 
"Arg_2不是数字");
        lua_error(L);
    }


    
/* GET ARGUMENT FROM STACK */
    
double a = lua_tonumber(L, 1); 
    
double b = lua_tonumber(L, 2);

    
/* PUSH RESULT TO STACK */
    lua_pushnumber(L, a 
* b);

    
/* COUNT OF RETURN VARS*/
    
return 1;
}



4. 程序解释

4.1 调用LUA脚本中的函数

调用LUA脚本函数主要用到如下几个LUA库函数:
    /* Push a FUNCTION_VAR to STACK */
    lua_getglobal(L, 
"fnex2");

    
/* Push PARAMETERS to STACK */
    lua_pushstring(L, szInParam);
    lua_pushnumber(L, iParam1);
    lua_pushnumber(L, iParam2);

    
/* Call FUNCTION in LUA */
    iError 
= lua_pcall( L,3,2,0);


通过lua_getglobal请求函数(指针)入栈,然后将函数参数按声明顺序入栈,调用lua_pcall执行函数。lua_pcall的第一个参数 指向LUA虚拟机,第二个参数表示栈顶有多少个函数参数,第三个参数表示此函数将返回几个值。(pcall自动清理入栈的参数,返回值则需要手动 pop。)

4.2 从LUA调用C函数

主要用到如下几个函数,为求方便您也可以自己定义这样的一个宏。
    lua_pushstring(L, "rmath");
    lua_pushcfunction(L, RMath_LUA);
    lua_settable(L, LUA_GLOBALSINDEX);

  • 函数名入栈
  • lua_CFunction类型的函数指针入栈
  • 调用lua_settable注册函数
这样就可以在lua脚本中调用rmath()函数了。
LuaLua Window 上的开发环境 SciTE 的安装,并运行第一个 Hello Lua LuaLua Window 上的开发环境 SciTE 的安装,并运行第一个 Hello Lua 目录 LuaLua Window 上的开发环境 SciTE 的安装,并运行第一个 Hello Lua 一、简单介绍 二、SciTE 下载地址 三、注意事项 四、SciTE 下载安装 五、在 SciTE 上运行第一个 Hello Lua 一、简单介绍 Lua 是... 阅读详情

相关推荐

Lua C/C++ 交互系列: Lua调用C/C++函数(3)

1、Lua API中提供注册C函数关键在lua_pushcclouse()函数。该函数可以在Lua Code中定义C函数。 但是Lua 提供了几个常用的宏定义,用于注册C函数。 这几个宏定义为: /#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_register(L,n,f) (lua_pu

sunning9001的专栏 1123

LUA调用C函数

文章目录前言Lua调用C的两种方式1. C函数进行调用2. C库进行调用 参考来源: 《Programming in Lua》中的第26章.调用C函数lua 5.3中文参考手册》 前言 lua通过一些方式实现对C函数调用lua高扩展性的体现。 Lua调用C的两种方式 lua调用C的两种方式其实是在不同的环境下去对C进行调用。 在C中通过lua的基础库函数调用C(通过C函数进行调用) 在lua调用C(对自己编译的C动态库进行调用) 无论是上面哪种方式去调用C函数,都必须遵

Dr_chaser的博客 2925

lua学习03:tolua的编译使用:C/C++调用lualua调用C++、lua调用tolua、常用tolualua的API介绍

文章目录一、编译及使用流程1)编译lua静态库2)编译tolua++静态库3)编译tolua++.exe4)根据C/C++文件编写好对应的pkg文件,然后根据一创命令生成tolua(1)C文件举例(2)C++文件举例二、C++调用lua三、lua调用C++ 一、编译及使用流程 1)编译lua静态库 必须先下载lua 1.5,下载好后,把/src目录的除开lua.c,luac.c的文件全部放到一个新建的静态链接库的工程项目里,然后编译出一个静态链接库lua.lib。 2)编译tolua++静态库 去tolua

谢白羽 3576

LuaC语言的互相调用

Lua底层是C语言开发的,在设计时就考虑到了C语言的互操作性。可以把Lua作为一种独立的语言或者作为一种嵌入式的脚本语言。有许多游戏其他应用程序利用Lua作为脚本语言。 在本文中,我们将重点探讨如何将Lua嵌入到C或C++应用程序中,作为胶水脚本存在。虽然此文只关注C语言的API,但在LuaDardo项目中,这些C API并没有做根本改变,只是在命名规范上做了适应Dart语言的变化(驼峰命名法)。简单说,LuaDardo基本是兼容这些API的。 使用 C API Lua的C语言API是高效轻量级的。在

编程之路的专栏 7675

Lua编译器及LuaC相互调用

Lua编译器及LuaC相互调用 2015-03-17 何鹏       Lua是一门小巧强大的编程语言,很多开发工具都对Lua源码进行了封装,本文用VS2012编译了Lua源码,并详细讲述了LuaC的互相调用。本文使用的是Lua5.1 一、Lua编译成解释器 1. 官网上下载源码:http://www.lua.org/ 2. 用VS2012新建一个解

buye1986的专栏 1451

lua语言调用 C函数

1.首先创建一个C的so函数库 huilib.c #include <stdio.h> #include <math.h> #include <stdarg.h> #include <stdlib.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> /* 所有注册给Lua的C函数具有 * "typedef int (*lua_CF.

weixin_40458727的博客 1237

luaC交互之——对lua数组的每个元素调用同一个函数

main.c #include <stdio.h> #include <string.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> static int l_map(lua_State* L) { int i, n; //第一个参数必须是一张表 luaL...

斧冰 664

在C语言中调用lua实现的回调函数

在内嵌的lua代码中,想要实现以下功能: function callback(n) print("function callback " .. n); end; save_callback(callback, "aaa") invoke_callback() -- 这里打印出function callback aaa save_callback(function(n) pri

superarhow的专栏 4334

c语言怎么调用lua函数,在C语言中调用lua实现的回调函数

在内嵌的lua代码中,想要实现以下功能:function callback(n)print("function callback " .. n);end;save_callback(callback, "aaa")invoke_callback() -- 这里打印出function callback aaasave_callback(function(n)print("anonymous func...

weixin_30516835的博客 461

Lua源码分析 - 栈结构篇 - 数据栈调用栈(03

Lua栈结构 - 栈存储方式 Lua栈结构主要是lua_State结构上。Lua的栈结构主要由两部分组成:数据栈调用栈 数据栈:主要由一个StkId结构的数组组成。所有的数据都通过lapi.c文件中的lua_push*函数向栈上压入不同类型的值(数字、字符串、函数等)。L->stack指向栈底部。每次将一个数据压入栈上,栈指针(L->top++)都会指向到下一个结构上。在栈结构初...

自娱自乐的代码人 8583

LuaC#交互③】方法调用错误处理函数

上篇文章简单说到了 lua_pcall 这个方法,不过没有考虑到参数返回值的情况,本节重点讲这个函数,还会讲如何把C#端的方法放在lua的栈上以供lua调用。 先上代码: var L = LuaDLL.luaL_newstate(); var path = Application.dataPath + "/Examples/03_Function/03.lua"; LuaDLL.luaL_l...

水鸡的游戏开发学习笔记 1791

luaC交互之—对lua数组的每个元素调用同一个函数

luaC交互之—对lua数组的每个元素调用同一个函数 lua程序栈的结构图:以先后传入两个参数"Hello" "Tip"为例 参考:LuaC/C++交互——Lua调用C/C++ 现在我们需要这样的一个功能,lua中一个数组,tb = {3, 4, 5, 6} ,调用一个function函数,得到的tb = {13, 14, 15, 16},需要这样的一个C库, main.c #include <stdio.h> #include <string.h> #include &lt

宁静致远的博客 360

C中调用Lua函数

我们先来看一个简单的例子: lua_State* L = NULL;// 内部调用lua函数 double f(double x, double y) { double z; lua_getglobal(L, "f"); // 获取lua函数f lua_pushnumber(L, x); // 压入参数xy lua_pushnumbe...

weixin_34077371的博客 371

Lua function

Lua调用是当一个函数的最后一个操作是调用另一个函数时,且没有涉及到其他函数,就形成了尾调用。尾调用不会开辟新的栈空间,而是直接返回到对应的最开始调用位置上。多返回值时,会一对一赋值对应变量,少于返回值的数目,则多出来的会被抛弃,多于返回值时,剩余部分会被赋值为 nil。函数调用其他语言一样,唯一不同的是,当函数只有一个参数时,且这个参数为字符串常量或表构造器。当函数调用时,不处于一系列表达式的最后,那么函数只会返回一个值,剩余的会被舍弃。Lua 函数是可以返回多个值,且值的类型并不固定。

有趣的博客 1242

C调用Lua函数

一:lua代码部分:新建一个lua文件,命名为HelloWorld.lua,代码如下: BoyName = "jon" local like = "apple" local function Hello(name, like)     print(string.format("Hello, %s!, you like %s", name, like)) end 里面包含了一

游子的博客 1599

lua调用c函数

环境配置 使用lua调用c语言编写的函数,首先要安装c语言的lua库,然后将其编译为动态链接库。 在Linux上直接使用apt-get安装的lua是没有自动安装lua库的,需要下载lua的源码编译安装。 编写c函数 如同main函数是所有c程序的入口程序一样,lua调用的c语言程序也有一个入口程序叫做luaopen_lib,其中lib是你自己的库的名字。除此之外,每个函数要传入的第一个参数必须是lua_State类型,也就是lua的stack。 luac之间的参数交换,是通过栈来完成的,也就是函数的第一

watqw的博客 1722

luaC交互(6):lua调用C函数

lua调用的C函数有一个一致的签名: typedef int (*lua_CFunction) (lua_State *L); 函数的返回值表示函数的返回值个数,luaC通过lua虚拟机中的栈来传递参数返回参数。 即C中的函数应该定义为: int testfunc(lua_State* L) { printf("testfunc from C"); return 0; } ...

心清的专栏 751

Lua 如何在Lua调用C/C++函数

Lua调用C函数有两种方式 1. 程序主体在C中运行,C函数注册到Lua中。C调用LuaLua调用C注册的函数,C或者Lua得到函数的执行结果。 2. 程序主体在Lua中运行,C函数作为库函数Lua使用。

HelloKandy's Blog 1314
上一篇: [LUA学习笔记02]在C中通过LUA API访问LUA脚本变量
下一篇: [LUA学习笔记04]Lua语法--数据类型
mrtechno
博客等级 码龄21年 9粉丝 12原创
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值