lua编程之lua与C相互调用
lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作。除此之外,lua还可以通过与C函数相互调用来扩展程序功能。在C中嵌入lua脚本既可以让用户在不重新编译代码的情况下修改lua代码更新程序,也可以给用户提供一个自由定制的接口,这种方法遵循了机制与策略分离的原则。在lua中调用C函数可以提高程序的运行效率。lua与C的相互调用在工程中相当实用,本文就来讲解lua与C相互调用的方法。
Lua与C相互调用的首要问题是如何交换数据,lua API使用了一个抽象的栈与C语言交换数据,提供了压入元素,查询元素和弹出元素等功能的API操作栈,这里可以查看lua5.2中每个函数的详细文档,栈中的元素可以通过索引访问,从栈底向上是从1开始递增的正整数,从栈顶向下是从-1开始递减的负整数,栈的元素按照FIFO的规则进出。
一、 C调用lua
先通过一个简单的例子了解C是怎么调用lua的,
//test.lua
width =
height = //test.c
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h> int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L); if(luaL_loadfile(L, "test.lua") || lua_pcall(L, ,,)){
printf("error %s\n", lua_tostring(L,-));
return -;
}
lua_getglobal(L,"width");
lua_getglobal(L,"length");
printf("width = %d\n", lua_tointeger(L,-));
printf("length = %d\n", lua_tointeger(L,-));
lua_close(L);
return ;
}
luaL_newstate创建一个新的lua_State,C和lua的所有操作都要依赖这个lua环境, luaL_openlibs将lualib.h中定义的lua标准库加载到进lua_State。
luaL_loadfile从文件中加载lua代码并编译,编译成功后的程序块被压入栈中,
lua_pcall会将程序块弹出并在保护模式下解释执行。代码中调用lua_pcall就在lua_State中定义了 width和 length两个全局变量。
lua_getglobal将全局变量的值压入栈中,width先入栈,在-2的位置,length在栈顶。
除了变量,C代码还可以直接调用lua中定义的函数
//test.lua
function add(x, y)
return x+y
end
//test.c
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <math.h> int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L); if(luaL_loadfile(L, "test.lua") || lua_pcall(L, ,,)){
printf("error %s\n", lua_tostring(L,-));
return -;
}
lua_getglobal(L,"add");
lua_pushnumber(L, );
lua_pushnumber(L, );
if(lua_pcall(L, , , ) != ){
printf("error %s\n", lua_tostring(L,-));
return -;
}
double z = lua_tonumber(L, -);
printf("z = %f \n", z);
lua_pop(L, );
lua_close(L);
return ;
}
lua_pcall(L, 2, 1, 0)表示,传入两个参数,期望得到一个返回值,0表示错误处理函数在栈中的索引值,压入结果前会弹出函数和参数,所以z的索引是-1.
二、 lua调用C
lua可以将C函数注册到lua中,C函数必须遵循统一的原型,这个原型定义在lua.h中,
typedef int (*) (lua_State *)
用C函数扩展lua时,一般将所有的C函数编译成一个独立的模块,方便增加新的函数。
//mylib.c
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <math.h> static int myadd(lua_State *L){
int a = luaL_checknumber(L, );
int b = luaL_checknumber(L, );
lua_pushnumber(L, a+b);
return ;
} static const struct luaL_Reg mylib [] = {
{"add", myadd},
{NULL, NULL}
}; int luaopen_mylib(lua_State *L){
luaL_newlib(L, mylib);
return ;
} //call.lua
#!/usr/local/bin/lua lib=require "mylib"
print(lib.add(, ))
每个被lua调用的C函数都有自己的私有栈,压入参数的索引从1开始递增,结果值也是直接压入栈中,函数返回时会将压入的参数全部删除,只留下结果值。mylib[]声明了模块中所有C函数列表,每一项映射了C函数在lua中的命名,比如上面代码中myadd函数在lua中用add表示,列表必须用{NULL, NULL}结束。 luaL_newlib在栈中创建一个table,将mylib数组中的C函数注册进这个table中。 luaopen_mylib将这个table中的函数加载进lua环境中。
先将C代码编译成动态链接库,
gcc -shared -fPIC -o mylib.so mylib.c -llua -lm -ldl
lua代码中,require会查找 mylib.so,并调用该链接库中的 luaopen_mylib,luaopen_的后缀必须与动态链接库名字一样,这是由require查找函数方式决定的。
lua编程之lua与C相互调用的更多相关文章
- iOS开发之OC与swift开发混编教程,代理的相互调用,block的实现。OC调用Swift中的代理, OC调用Swift中的Block 闭包
本文章将从两个方向分别介绍 OC 与 swift 混编 1. 第一个方向从 swift工程 中引入 oc类 1. 1 如何在swift的类中使用oc类 1.2 如何在swift中实现oc的代理 ...
- C++混合编程之idlcpp教程Lua篇(7)
上一篇在这 C++混合编程之idlcpp教程Lua篇(6) 第一篇在这 C++混合编程之idlcpp教程(一) 与LuaTutorial4工程相似,工程LuaTutorial5中,同样加入了四个文件: ...
- C++混合编程之idlcpp教程Lua篇(6)
上一篇在这 C++混合编程之idlcpp教程Lua篇(5) 第一篇在这 C++混合编程之idlcpp教程(一) 工程LuaTutorial4中加入了四个文件:LuaTutorial4.cpp, Tut ...
- C++混合编程之idlcpp教程Lua篇(5)
上一篇在这 C++混合编程之idlcpp教程Lua篇(4) 第一篇在这 C++混合编程之idlcpp教程(一) 与前面的工程相似,工程LuaTutorial3中,同样加入了三个文件:LuaTutori ...
- C++混合编程之idlcpp教程Lua篇(4)
上一篇在这 C++混合编程之idlcpp教程Lua篇(3) 与前面的工程相似,工程LuaTutorial2中,同样加入了三个文件 LuaTutorial2.cpp, Tutorial2.i, tut ...
- C++混合编程之idlcpp教程Lua篇(3)
上一篇 C++混合编程之idlcpp教程Lua篇(2) 是一个 hello world 的例子,仅仅涉及了静态函数的调用.这一篇会有新的内容. 与LuaTutorial0相似,工程LuaTutoria ...
- C++混合编程之idlcpp教程Lua篇(2)
在上一篇 C++混合编程之idlcpp教程(一) 中介绍了 idlcpp 工具的使用.现在对 idlcpp 所带的示例教程进行讲解,这里针对的 Lua 语言的例子.首先看第一个示例程序 LuaTuto ...
- Lua 与 OC 相互调用
本文主要讲如何完成lua和object-c的相互调用. lua是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...
- C程序与Lua脚本相互调用
Lua脚本是一种可用于C程序开发/测试的工具,本篇介绍一下C程序与Lua脚本如何进行相互调用,更加详细的操作参见<Programing in Lua>.本文分为3个部分:1.Windows ...
随机推荐
- C#调用开源图像识别类库tessnet2
首先下载tessnet2_32.dll及相关语言包,将dll加入引用 private tessnet2.Tesseract ocr = new tessnet2.Tesseract();//声明一个O ...
- Linux学习笔记:JDK安装
系统为CentOS 7,安装Oracle jdk1.8 卸载系统自带的Openjdk(若无可跳过这一步,可以通过 java -version 查看),步骤是:查找Openjdk,卸载Openjdk r ...
- 一个简单的NodeJs静态页面的web服务器
主要功能 1 显示www文件夹下静态html或文本类型的文件. 2 缺省访问文件功能. 通过config.js的defaultfile属性设置 3 如果文件夹下没有缺省文件,显示文件夹下文件列表 4 ...
- TensorFlow安装时错误CondaValueError: prefix already exists: G:\softs\Anaconda\envs\tensorflow
TensorFlow安装时,TensorFlow环境已经调好了,就是下面的第(3)步, 可我自己偏偏选了个Python3.7,因为检测到自己的Python最新版本为3.7,就手贱安了TensorFlo ...
- 【C#】解析C#中JSON.NET的使用
目录结构: contents structure [-] JSON.NET简介 Serializing and Deserializing JSON Json Convert Json Seriali ...
- js中实现 复制到剪切板 功能
一:引包 <script type="text/javascript" src="jquery.js"></script> <sc ...
- swift -inout关键字
一般参数仅仅是在函数内可以改变的,当这个函数执行完后变量就会被销毁,不会有机会改变函数以外的变量,那么我们就会产生一个疑问,我们可不可以通过一个函数改变函数外面变量的值呢?答案是肯定的,这时我们就需要 ...
- Java获取文件后缀名
int dot = filename.lastIndexOf('.'); if ((dot > -1) && (dot < (licenceImg.getOriginalF ...
- windows10; ERROR 1010 (HY000): Error dropping database (can't rmdir './test/', errno: 17);默认数据库位置查找
1.想要导入数据到一个数据库中,但是,无法导入,同时也无法删除数据库重新建立-----------------------------备份当前数据库 2,分析:很多资料显示说数据库下有异常文件,于是就 ...
- IntelliJ IDEA 2017版 使用笔记(五) 模板 live template自定义设置(二) ;postfix使用;IDE快捷键使用
一.live template 活模板 就像这个单词的含义一样,live template就是一个高效的提高代码,书写速度的方式,(live template位置File-----settin ...