[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, 0, 0, 0);
    
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, 0, 0, 0);
    
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()函数了。
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 阅读详情

相关推荐

C++ 调用 Lua 函数

Lua 作为一门脚本语言,可以作为 “配置文件”、“动态逻辑脚本” 等角色作用于宿主程序。1. Lua 会处理语法细节,后续维护简单,并且可以有注释。2. 可以编写逻辑,达到复杂的配置。如果我们的程序需要进行一些 “下发配置” 时,一般会考虑选择 “json”、“文件” 等形式。但是如果 “配置” 内容较为复杂,则可以考虑 Lua 了,具体可以查看以下分享。Github传送门(如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)如果觉得本篇博文对你有所启发或是解决了困惑,。

江澎涌的博客 1404

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的博客 2947

lua学习03:tolua的编译和使用:C/C++调用lua、lua调用C++、lua调用tolua、常用tolua和lua的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

谢白羽 3603

Lua与C语言的互相调用

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

编程之路的专栏 7725

5G时代必知:LDPC与Polar码实战解析(附MATLAB仿真代码)

本文深入解析5G时代核心信道编码技术LDPC码与Polar码的原理差异及性能表现,通过MATLAB仿真代码展示其在实际通信系统中的应用。LDPC码适用于大数据块高速传输,而Polar码在小数据块低时延场景表现优异,帮助开发者优化5G系统设计。

sugar的博客 642

高速设计注意事项总结——MDI篇

在以太网高速通信系统中,MDI(Medium Dependent Interface,介质相关接口)是连接物理层芯片(PHY)与传输介质(如网线)的关键接口,其设计直接影响信号完整性、传输速率和抗干扰能力。本文围绕 MDI 及 RJ45 接口电路、关键参数、设计与布线要点展开,为高速以太网设计提供参考。本文包含MDI 及 RJ45 接口电路组成、电路设计注意事项、布局布线要求等内容

qq_16237389的博客 1445

Lua编译器及Lua与C相互调用

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

buye1986的专栏 1454

CANoe的安装教程

CANoe的安装教程

weixin_59090531的博客 1万+

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的博客 1240

C#读取CAD文件(dwg/dxf)并处理

项目要求识别CAD图纸(图纸内容与现实事物比例是1:1)中的内容,并提取出一些关键信息。这里的CAD图纸是指CAD文件,包含多种格式,dwg/dxf/dwf/stl/pdf等等。识别其中内容,主要指文件中的图元信息(也叫实体Entity),指线段、圆弧、矩形等图形元素。得到图元基础信息(比如长度、坐标、粗细)后,进一步做处理(如得到交点、得到线段间间隔、圆弧与线段切点等)。听起来有点难,因为作为软件工程师,对CAD相关事物并不了解,它是未知的;

三千幻想乡 1万+

TI CC2642R蓝牙5.2模块实战:从零搭建智能门锁原型(附电路图)

本文详细介绍了如何基于TI CC2642R蓝牙5.2模块从零搭建智能门锁原型,涵盖硬件选型、低功耗配置、蓝牙安全交互等关键环节。通过CC2642R的高性能MCU和蓝牙5.2技术,开发者可实现低功耗、高安全性的智能门锁设计,并提供实用的电路图和PCB布局建议。

o5p6q的博客 109

lua与C交互之——对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...

斧冰 665

爬取二手房数据:Python爬虫+Geopy实战,看透房价与地理位置的隐藏关系

哪些区域单价虚高(房源少但单价远高于周边);哪些小区性价比高(靠近地铁/学校,单价低于同地段平均水平);房价与地理位置的量化关系(如距离地铁每远1公里,单价下降多少)。如果想扩展分析范围,可爬取多个城市/区域的数据,对比不同城市的房价差异;或结合时间维度(定期爬取),分析房价的涨跌趋势。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 948

在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的专栏 4339

实战复盘:纷玩岛(Livelab)候补订单微信支付协议的逆向与复现

通过本次对纷玩岛候补支付接口的分析,我们实现了一个脱离 App UI 的轻量级支付发起器。这不仅验证了其API的设计逻辑(Standby -> PrePayInfo 分层设计),也为后续的自动化监控或辅助抢票工具提供了支付环节的技术验证。技术本无罪,关键在于如何使用。理解这些底层协议,有助于我们写出更健壮的代码,也能在遇到线上支付问题时快速定位是业务层(API)问题还是通道层(微信)问题。

猫敷雪 796

uniapp [安卓苹果App端] - 解决支付宝支付报错requestPayment:fail [payment支付宝:62009]未知错误,使用uni.requestPayment支付报错排查方案

uni-app支付宝,uniapp支付宝沙箱支付报错,uni.requestPayment,uniAPP App支付宝支付提示错误requestPayment:fail [payment支付宝:62009]未知错误,UNI-APP支付宝报错"code": -100,uniapp 解决安卓App使用uni.requestPayment实现沙箱环境支付宝支付报错,uniapp安卓app使用支付宝的沙箱环境支付时报了这个错,安卓端app支付宝支付,在沙箱测试环境测支付,提示“商家订单参数异常,请重新发起付款,选择

🏆 前端领域优质创作者 9609

【2014-09-03】Lua快速学习笔记:在Lua脚本中调用C/C++函数的API

Lua学习笔记,介绍在Lua脚本中调用C/C++函数的机制,包括lua_CFunction的编写规范、使用lua_register注册C函数到Lua环境、参数和返回值通过Lua栈传递的完整示例。

cstriker1407的专栏 23

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

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的博客 464

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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

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

自娱自乐的代码人 8621

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【Lua与C#交互③】方法调用和错误处理函数

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

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

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

lua与C交互之—对lua数组的每个元素调用同一个函数 lua程序栈的结构图:以先后传入两个参数"Hello" "Tip"为例 参考:Lua与C/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

0基础lua学习(十九)C调用Lua----03C调用lua 函数和变量

下面的demo,主要演示 C如何访问 Lua中 函数、变量。 lua代码 function add(x,y) print("add") return x + y end width = 100 height= 200 background = {r=0, g=0, b=1} C代码 extern "C" { #include #inclu

小鱼酱的博客 747

LUA 调用C代码的 通用方式

LUA 调用C代码的 通用方式 测试环境 c4droid 懒人精灵 雷电模拟器 C代码: int argc, char* argv[]: argc参数个数 传入的字符串数组 下面展示一些 内联代码片。 // An highlighted block #include <stdio.h> int main(int argc, char* argv[]) { puts("C语言中文网"); puts(argv[2]); puts("w sh bas "); retu

qq_27684977的博客 589

【2014-09-03】Lua快速学习笔记:如何在C函数中保存状态

Lua学习笔记,介绍在C函数中保存持久状态的方法,包括使用Lua注册表(registry)、使用upvalue(闭包变量)存储C侧状态数据,避免使用全局C变量带来的多Lua环境冲突问题。

cstriker1407的专栏 23

lua pcall 返回值_【Lua与C#交互③】方法调用和错误处理函数

上篇文章简单说到了 lua_pcall 这个方法,不过没有考虑到参数和返回值的情况,本节重点讲这个函数,还会讲如何把C#端的方法放在lua的栈上以供lua调用。先上代码:var Lua代码如下:function 结果是先打印-10,再打印30函数、参数、返回值的入栈顺序上面的各个方法之前我们已经学过了,这里需要理解 函数、参数、返回值的入栈顺序。如图所示: - 先将方法入栈 - 再将方法需要的参...

weixin_39611754的博客 347

lua C语言api学习2 在C语言中使用lua语言

lua C语言api学习2 在C语言中使用lua语言

sinat_41629921的博客 604
上一篇: [LUA学习笔记02]在C中通过LUA API访问LUA脚本变量
下一篇: [LUA学习笔记04]Lua语法--数据类型
mrtechno
博客等级 码龄21年 9粉丝 12原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值