lua—C/C++lua嵌入式开发

原文链接:https://blog.csdn.net/sm9sun/article/details/68946343

首先介绍一下Lua语言,Lua 是一个小巧的脚本语言,该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

一、lua定位——C/C++嵌入式脚本语言

lua本身就是C写的,所以Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数
lua语法、解释器、执行原理都与python相似
唯一差距就是lua没有强大的类库作为支撑,Lua只是具备了一些比如数学运算和字符串处理等简单的基本功能。
所以lua不适合作为开发独立应用程序的语言。

二、数据类型——table

lua本质上只有一种数据类型,就是table,实际上就是hash表。它用这个来模拟数组,链表等等。

比如说,lua代码:

data = {} --定义一个table
data.i = 1
data.name = "jason"
data.package = {1,2,2,3,56,7}
data.others = {}
data.others.a = 1
data.others.b = 1.1

等于C的结构体struct

三、协程

Lua所支持的协程全称被称作协同式多线程(collaborative multithreading)。Lua为每个coroutine提供一个独立的运行线路。然而和多线程不同的地方就是,coroutine只有在显式调用yield函数后才被挂起,同一时间内只有一个协程正在运行。他的主要优势就是线程执行序列显示可控。然而归根结底协程还是串行的。

下面重点说一下Lua与C/C++之间的交互

首先,Lua和C程序通过struct lua_State堆栈交换数据,这点和python类似,python是通过python对象进行交互。(*Lua 调用C函数用的堆栈是临时的,调用结束之后就被销毁了。)堆栈索引的方式可是是正数也可以是负数,正数索引1永远表示栈底,负数索引-1永远表示栈顶

【一】基本配置

首先导入相关的头文件及库(安装目录下的include和lib),这个就不多说了。顺便一提,我的lua版本为5.1。

然后就是创建交换数据用的 lua_State 堆栈了,

lua_State *L = lua_open();        //创建lua_State *L堆栈

然后用luaL_openlibs进行初始化

luaL_openlibs(L);                  //初始化

这个命名蛮尴尬的,官方的说明大概的意思就是把所有标准库加载到这个指定的L里把= =
顺带一提,加载某个标准库的话就是luaL_openlib了- -然而这根本就是两个不同的事嘛!

与其相应的 结尾肯定要释放咯~

lua_close(L);                   //释放

以上就是调试前基本的配置了。

【二】进行交互

C++与Lua交互的方式主要为luaL_dostring(通过直接传入字符串(Lua代码)的方式)以及luaL_dofile(加载指定Lua脚本文件)

例如:

const char *buf = "print('hello, lua!')";     
 
//可以用dostring这种方式直接执行lua代码
luaL_dostring(L, buf);             
 
//也可以用dofile这种方式打开lua文件
luaL_dofile(L, "...\Test.Lua);

【三】获取Lua参数

上文中说过,C++与Lua交互主要通过堆栈进行,对于C++这边,传参就是lua_push,获取就是lua_to。后面对应的数据类型

如将int入栈,即lua_pushnumber,如获取string参数,即lua_tostring,他们参数都是两个,堆栈L及一个索引参数,比如说-1为栈顶,-2就是第二个~

例:

Lua代码

–用于测试C++获取lua参数

var1=111
var2=222
var3=333

C++代码

//获取lua参数
 
	lua_pushstring(L, "var1"); //将变量的名字放入栈  
 
    lua_gettable(L, LUA_GLOBALSINDEX);//通过栈顶的索引定位到参数值并放至栈顶
 
	lua_pushstring(L, "var2"); //将变量的名字放入栈 
 
	lua_gettable(L, LUA_GLOBALSINDEX);//通过栈顶的索引定位到参数值并放至栈顶
 
	int var1 = lua_tonumber(L, -1);
 
	int var2 = lua_tonumber(L, -2);
 
	cout << "var1:" << var1 << endl << "var2:" << var2 << endl;
 
	lua_getglobal(L, "var3");        //lua定义的宏,直接找var3
 
	int var3 = lua_tonumber(L, -1);
 
	cout << "var3:" << var3 << endl;

输出为:
var1:222
var2:111
var3:333

我们先看上文中提到的数据类型,Lua的数据类型本质是Table,也就是说,我们首先将Key为var1的变量名放入栈顶,再通过gettable来获取对应的Value

再将Value放到栈顶。然后C++通过lua_to函数获取这个参数值。

我们先将var1放入栈顶,又将var2放入栈顶,这样当我们取-1的时候 实际去的是var2,-2是之前的var1,所以我们看到 var1和var2的值进行了互换。

同时,Lua也提供了一个lua_getglobal函数直接取这个变量,也适用于取函数(后文会提到)。

【四】调用lua方法

lua代码

--用于测试lua多返回
function f1(a,b,c)
 local sum=a+b
 return sum,c
end

C++代码

//调用lua方法
 
	lua_getglobal(L, "f1");    //在Lua中,函数等同于变量,所以你可以这样来取得这个函数
	lua_pushnumber(L, 100);    //将参数1压栈
	lua_pushnumber(L, 20);     //将参数2压栈
	lua_pushstring(L, "function f1");  //将参数3压栈
 
	//LUA_API int   (lua_pcall)(lua_State *L, int nargs, int nresults, int errfunc);
	lua_pcall(L, 3, 2, 0); //调用函数,3个参数,2个返回值
 
	string result1 = lua_tostring(L, -1);
	int result2    = lua_tonumber(L, -2);
	cout << "result1:" << result1 << endl; 
	cout << "result2:" << result2 << endl;

看,lua_getglobal同时适用于调取某个全局函数,然后通过lua_push来将参数压栈。

lua_pcall执行函数,其参数为堆栈,参数个数,返回值个数,错误处理(一般不需要Lua进行处理,所以是0)

再通过lua_to获取返回值,这里我们看到,Lua代码中返回的是sum(int),c(string)

所以,栈顶是c(string),第二个是sum(int)。

输出为:

result1:function f1
result2:120

【五】lua调用C++函数

lua代码

--用于测试lua调用C++函数

function f2(a,b,c)
 local len=lua_Strlen(c)
 local sum=a+b+len
 return sum
end

C++代码

调用函数

int lua_Strlen(lua_State *L)
{
	//首先取出脚本执行这个函数时压入栈的参数  
	//假设这个函数提供一个参数,有一个返回值  
 
	//get the first parameter  
	const char *par = lua_tostring(L, -1);
 
	cout << "at lua_Strlen,the str is :"<<par << endl;
 
	//push the first result  
	lua_pushnumber(L, strlen(par));
	return 1;
}

主函数

//lua调用C++函数
 
	lua_register(L, "lua_Strlen", lua_Strlen); //注册函数
 
	lua_getglobal(L, "f2");
	lua_pushnumber(L, 100);
	lua_pushstring(L, "20");
	lua_pushstring(L, "abc");
    lua_pcall(L, 3, 1, 0); //调用函数,3个参数,1个返回值  
 
	int result3 = lua_tonumber(L, -1);
 
	cout <<"result3:" << result3 << endl;

我们先看调用函数,一样是通过to获取参数,通过push将函数打入栈中给Lua传递,

调用函数的参数为堆栈L,返回值为返回参数的个数。这里我们做一个简单的strlen函数

再来看主函数这边,首先需要将调用函数strlen进行注册,然后是调用Lua里的f2函数,和上面的类似。

大家看,我的第二个参数传入的是string类型:lua_pushstring(L, “20”); 说明Lua是可以进行隐性强转的。

即我们在C++调用Lua前先将调用函数入栈,之后调用Lua脚本的f2函数,当f2函数执行到local len=lua_Strlen©时会在栈中寻找相应的方法

于是调用了C++我们写好的调用函数lua_Strlen,参数之间都是通过栈顶进行交互传递的

输出为:

at lua_Strlen,the str is :abc
result3:123

完整测试代码:

Test.Lua

-用于测试C++获取lua参数

var1=111
var2=222
var3=333



--用于测试lua多返回
function f1(a,b,c)
 local sum=a+b
 return sum,c
end


--用于测试lua调用C++函数

function f2(a,b,c)
 local len=lua_Strlen(c)
 local sum=a+b+len
 return sum
end

Lua_test.cpp

// lua_test.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
 
 
extern "C"
 
{
#include "lua.h"  
#include "lauxlib.h"  
#include "lualib.h"  
 
}
 
 
int lua_Strlen(lua_State *L)
{
	//首先取出脚本执行这个函数时压入栈的参数  
	//假设这个函数提供一个参数,有一个返回值  
 
	//get the first parameter  
	const char *par = lua_tostring(L, -1);
 
	cout << "at lua_Strlen,the str is :"<<par << endl;
 
	//push the first result  
	lua_pushnumber(L, strlen(par));
	return 1;
}
 
 
int main()
{
	
 
    lua_State *L = lua_open();        //创建lua_State *L堆栈
 
	luaL_openlibs(L);                  //初始化
 
	const char *buf = "print('hello, lua!')";     
 
	//可以用dostring这种方式直接执行lua代码
	luaL_dostring(L, buf);             
 
 
	//也可以用dofile这种方式打开lua文件
	luaL_dofile(L, "..\\Test.txt");
 
 
	//获取lua参数
 
	lua_pushstring(L, "var1"); //将变量的名字放入栈  
 
    lua_gettable(L, LUA_GLOBALSINDEX);//通过栈顶的索引定位到参数值并放至栈顶
 
	lua_pushstring(L, "var2"); //将变量的名字放入栈 
 
	lua_gettable(L, LUA_GLOBALSINDEX);//通过栈顶的索引定位到参数值并放至栈顶
 
	int var1 = lua_tonumber(L, -1);
 
	int var2 = lua_tonumber(L, -2);
 
	cout << "var1:" << var1 << endl << "var2:" << var2 << endl;
 
	lua_getglobal(L, "var3");        //lua定义的宏,直接找var3
 
	int var3 = lua_tonumber(L, -1);
 
	cout << "var3:" << var3 << endl;
 
 
 
	//调用lua方法
 
	lua_getglobal(L, "f1");    //在Lua中,函数等同于变量,所以你可以这样来取得这个函数
	lua_pushnumber(L, 100);    //将参数1压栈
	lua_pushnumber(L, 20);     //将参数2压栈
	lua_pushstring(L, "function f1");  //将参数3压栈
 
	//LUA_API int   (lua_pcall)(lua_State *L, int nargs, int nresults, int errfunc);
	lua_pcall(L, 3, 2, 0); //调用函数,3个参数,2个返回值
 
	string result1 = lua_tostring(L, -1);
	int result2    = lua_tonumber(L, -2);
	cout << "result1:" << result1 << endl; 
	cout << "result2:" << result2 << endl;
 
 
	//lua调用C++函数
 
	lua_register(L, "lua_Strlen", lua_Strlen); //注册函数
 
	lua_getglobal(L, "f2");
	lua_pushnumber(L, 100);
	lua_pushstring(L, "20");
	lua_pushstring(L, "abc");
    lua_pcall(L, 3, 1, 0); //调用函数,3个参数,1个返回值  
 
	int result3 = lua_tonumber(L, -1);
 
	cout <<"result3:" << result3 << endl;
 
	lua_close(L);                   //释放
 
	system("pause");
	return 0;
}

VS运行截图

在这里插入图片描述

嵌入式linux lua,在自己的工程中嵌入Lua脚本引擎

https://blog.csdn.net/weixin_35284593/article/details/116830399?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-5.pc_relevant_default&spm=1001.2101.3001.4242.4&utm_relevant_index=7

Lua语言被不少大软件作为脚本语言,因为通过Lua语言,可以很方便地调用大型程序中的已有函数,这样可以将业务逻辑与算法逻辑分离开。我们也可以在自己的软件中,嵌入lua语言,预留API给用户做更多的自定义操作(如脚本编辑器)。本文谈Lua源码的编译、以及如何在自己的C程序中嵌入Lua。

编译Lua

在Lua官网的http://www.lua.org/download.html页面,可以下载到各个版本的Lua源码。源码的结构分为以下几个目录:

doc:文档

etc:方便学习的lua源码,是工程级别的lua的子集,含Makefile

source:lua源代码,含Makefile

test:一些Lua脚本,用于测试

根据源文件生成Lua,最终的结果有几种选择:

Lua library:静态的Lua库,这样,配合Lua的头文件,就可以将Lua嵌入到自己的程序中了

Standalone Lua:Lua解释器,可以读取Lua脚本并执行

Luac:lua编译器,将Lua脚本翻译成Lua字节码,这样可以加快Lua脚本的加载速度

源码附带的Makefile,没有针对Windows VS平台的选项。不过不用担心,自己根据需要,建个空工程,再把各个文件添加进去,就可以编译成功了。其中luac与lua需要建立的是控制台空工程,静态库需要建立的是静态库空工程(链接方式不一样)。

嵌入Lua

编译好lualib后,就可以配合头文件,在自己的C++程序中调用Lua了,以下是一个简单例子,它加载并执行一个Lua脚本"hello,lua":

extern "C" {undefined

#include "LuaHeader/lua.h"

#include "LuaHeader/lualib.h"

#include "LuaHeader/lauxlib.h"

}

int main(int argc, char *argv[])

{undefined

int s = 0;

lua_State *L = lua_open();

// load the libs

luaL_openlibs(L);

//run a Lua scrip here

luaL_dofile(L, "hello.lua");

lua_close(L);

return 1;

}

因为Lua是C语言写的,为了链接正常,注意要extern “C”。以下是hello.lua脚本的内容,它也可以修改为其它符合lua语法的脚本:

io.write("Please enter your name: ")

name = io.read()

io.write("Hi " .. string.format("%s",name) .. ", enjoy hacking with Lua\r\n");

用Lua中调用host程序的函数

lua常被选为各大程序的内嵌脚本语言的原因,就是它可以将host program的函数,注册为API供lua调用,这样可以使编程的逻辑易于调整。以下是一个特别简单的例子:

// function type must be lua_CFunction

extern "C" static int MYAPI_ShowHello(lua_State *L)

{undefined

printf("Hello, World\r\n");

return 1;

}

int main(int argc, char *argv[])

{undefined

int s = 0;

lua_State *lua = lua_open();

// load the libs

luaL_openlibs(lua);

// register C function into lua

lua_pushcclosure(lua, MYAPI_ShowHello, 0);

lua_setglobal(lua, "myHello");

//run a Lua scrip here

luaL_dofile(lua, "hello.lua");

lua_close(lua);

return 1;

}

通过以上pushcclosure与setglobal的注册,在lua中可以通过调用"myHello"来间接调用host程序的MYAPI_ShowHello函数。

"hello.lua"中的内容:

myHello()

Lua脚本在C++下的舞步(入门指引)(转)

https://blog.csdn.net/aigao1992/article/details/101561813?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164516460316781683990502%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164516460316781683990502&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-5-101561813.pc_search_result_positive&utm_term=lua

Lua教程

https://blog.csdn.net/qq_33670157/article/details/104455299?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164516460316781683990502%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164516460316781683990502&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-4-104455299.pc_search_result_positive&utm_term=lua&spm=1018.2226.3001.4187

Lua开发工具LuaEdit

https://blog.csdn.net/weixin_39510813/article/details/95241163

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: LuaC++可以通过Lua C API来实现互相调用。具体步骤如下: 1. 在C++中,使用Lua C API创建一个Lua状态机。 2. 在C++中,将需要在Lua中调用的函数或对象注册到Lua状态机中。 3. 在Lua中,使用require函数加载C++编写的模块。 4. 在Lua中,调用已注册的C++函数或对象。 例如,假设我们有一个C++中的函数add,它可以将两个整数相加。我们将它注册到Lua状态机中,并在Lua中调用它: C++代码: ```cpp int add(lua_State* L) { int a = luaL_checkint(L, 1); int b = luaL_checkint(L, 2); int sum = a + b; lua_pushinteger(L, sum); return 1; } int main() { lua_State* L = luaL_newstate(); luaL_openlibs(L); lua_register(L, "add", add); lua_close(L); return 0; } ``` Lua代码: ```lua require "example" print(add(1, 2)) -- 输出3 ``` 需要注意的是,使用Lua C API需要对LuaC++有一定的了解,同时需要注意内存管理等问题,以避免出现内存泄漏等问题。 ### 回答2: Lua是一种脚本语言,而C是一种编程语言。它们可以互相调用,这使得开发者可以利用各自的优势来实现更强大和高效的应用程序。 Lua与C的互相调用主要是通过提供Lua与C之间的接口,使得它们可以共享数据和函数。在Lua中,可以使用C API(应用程序编程接口)来调用C函数,而在C中,可以使用Lua API来调用Lua函数。 在Lua中调用C函数可以通过使用C API的相关函数来实现。开发者可以在C中编写函数,然后在Lua中通过调用lua_pcall函数来调用这些函数。在C函数中,可以通过lua_push*函数将结果返回给Lua,使得Lua可以进一步处理。 而在C中调用Lua函数可以通过使用Lua API的相关函数来实现。首先,需要创建一个Lua状态机,然后加载和执行Lua脚本。在C中可以使用lua_get*函数获取Lua函数的引用,以便后续调用。使用lua_call函数可以直接调用Lua函数,也可以使用lua_pcall函数来进行错误处理。 通过Lua与C的互相调用,可以发挥Lua的灵活和简洁的脚本特性,同时利用C的强大性能和控制能力。这使得开发者可以在Lua中快速编写脚本逻辑,同时使用C来处理性能敏感的计算和底层操作。通过这种方式,可以有效地提高应用程序的性能和效率。 总而言之,Lua和C是可以互相调用的,通过适当的API使用,可以将两者的优势结合在一起,实现更加灵活高效的应用程序。 ### 回答3: 在Lua和C之间进行互相调用是非常常见且有用的操作。这种能力使得我们可以利用C的性能优势来提高Lua脚本的执行效率,并且可以在C代码中引用Lua的功能和特性。 Lua和C之间的互调可以通过一些接口函数来完成。首先,C代码可以通过嵌入式Lua库来初始化和创建一个Lua状态机。然后,我们可以通过C代码将一些C函数注册到Lua状态机中,使得这些函数可以被Lua脚本中的代码所调用。 另一方面,我们也可以在Lua脚本中调用C函数。首先,我们需要使用`require()`函数来加载和执行C代码中注册的Lua模块。然后,我们可以直接通过模块中定义的函数来调用C函数,并且可以传递参数和获取返回值。 通过这种互相调用机制,Lua和C之间可以实现近乎无缝的交互。对于Lua脚本来说,我们可以利用C函数来完成一些复杂、高性能的任务,例如图形渲染,网络通信等。而对于C代码来说,我们可以利用Lua的易用性和快速开发的特性来编写和调试一些快速迭代的功能。 总而言之,Lua和C之间的互相调用能够充分发挥各自的优势,为我们提供了更强大、灵活和高效的开发和编程环境。无论是在游戏开发、嵌入式系统还是其他领域,这种能力都是非常有价值的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值