lua 与 c 的相互调用
Lua是一个嵌入式的语言,意味着Lua不仅可以是一个独立运行的程序包也可以是一个用来嵌入其他应用的程序库。
Lua可以作为程序库用来扩展应用的功能,也就是Lua可以作为扩展性语言的原因所在。同时,Lua程序中可以注册有其他语言实现的函数,这些函数可能由C语言(或其他语言)实现,可以增加一些不容易由Lua实现的功能。这使得Lua是可扩展的。与上面两种观点(Lua作为扩展性语言和可扩展的语言)对应的C和Lua中间有两种交互方式。第一种,C作为应用程序语言,Lua作为一个库使用;第二种,反过来,Lua作为程序语言,C作为库使用。这两种方式,C语言都使用相同的API与Lua通信,因此C和Lua交互这部分称为C API。
C API是一个C代码与Lua进行交互的函数集。他由以下部分组成:读写Lua全局变量的函数、调用Lua函数的函数、运行Lua代码片断的函数、注册C函数然后可以在Lua中被调用的函数等。
当在Lua和C之间交换数据时我们面临着两个问题:动态与静态类型系统的不匹配和自动与手动内存管理的不一致。解决办法是在C和Lua之间通信关键在于一 个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。因为栈是由Lua来管理的,垃圾回收器知 道那个值正在被C使用。
C API中的大部分函数并不检查他们参数的正确性;你需要在调用函数之前负责确保参数是有效的。
Lua以一个严格的LIFO规则(后进先出;也就是说,始终存取栈顶)来操作栈:
(1)当你调用Lua时,它只会改变栈顶部分。
(2)你的C代码却有更多的自由;更明确的来讲,你可以查询栈上的任何元素,甚至是在任何一个位置插入和删除元素。
在调用C API时有几个重要的头文件:
(1)lua.h:Lua基础函数库,lua_前缀
(2)lauxlib.h:辅助库,luaL_前缀,利用lua.h实现的更高层的抽象
(3)lualib.h:为了保持Lua的苗条,所有的标准库以单独的包提供,所以如果你不需要就不会强求你使用它们。头文件lualib.h定义了打
开这些库的函数。例如,调用luaopen_io,以创建io table并注册I/O函数(io.read,io.write等等)到Lua环境中。
API用索引来访问栈中的元素。栈底为1,依次往上增加,也可用负数索引,-1表示栈顶元素。下面列出一些常用的C API函数:
lua_push*:压入栈元素
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
lua_to*:从栈中获得值。即使给定的元素类型不正确,调用这些函数也没问题。
int lua_toboolean (lua_State *L, int index);
double lua_tonumber (lua_State *L, int index);
const char * lua_tostring (lua_State *L, int index);
Lua_tostring函数返回一个指向字符串的内部拷贝的指针。你不能修改它(使你想起那里有一个const)。只要这个指针对应的值还在栈内,Lua会保证这个指针一直有效。当一个C函数返回后,Lua会清理他的栈,所以,有一个原则:永远不要将指向Lua字符串的指针保存到访问他们的外部函数中。
size_t lua_strlen (lua_State *L, int index):返回字符串的实际长度。
int lua_checkstack(lua_State *L, int sz):检查栈空间。默认有20个空闲的记录,lua.h中的LUA_MINSTACK宏定义了这个常量。
int lua_is... (lua_State *L, int index):检查一个元素能否被转换成指定的类型。
int lua_type (lua_State *L, int idx):返回栈中元素的类型;
const char* lua_typename(lua_State *L, int tp):返回type对应的名字字符串,第二个参数为lua_type返回的类型
void luaL_checktype (lua_State *L, int arg, int t):返回参数arg是否是类型t,第三个参数为lua_type的取值。
在lua.h头文件中,每种类型都被定义为一个常量:LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD。
int lua_gettop (lua_State *L):返回栈中元素个数,它也是栈顶元素的索引。
void lua_settop (lua_State *L, int index):设置栈顶元素的索引,相当于设置栈的大小。如果开始的栈顶高于新的栈顶,顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的 空值(nil)到栈上。lua_settop(L,0):清空堆栈。
#define lua_pop(L,n) lua_settop(L, -(n)-1):宏定义,弹出n个元素。
void lua_pushvalue (lua_State *L, int index):压入堆栈上指定索引的一个抟贝到栈顶,等于拷贝index处的元素,然后添加到栈顶。
void lua_remove (lua_State *L, int index):移除指定索引的元素,并将其上面所有的元素下移来填补这个位置的空白。
void lua_insert (lua_State *L, int index):移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空隔。
void lua_replace (lua_State *L, int index):从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作。
实践部分:
1.lua 环境安装
到http://www.lua.org/versions.html下载lua安装包(此处为5.1.5.tar.gz)
解压后执行make linux
2.lua之小试牛刀
编辑first.lua
print("lua program")
编译first.lua
lua first.lua
-->lua program
3. c 调用lua
编写first.c调用first.lua
/---first.c---/
int main(int argc, char *argv[])
{
/*initialize Lua*/
L = lua_open();
/*load Lua base libraries*/
luaL_openlibs(L);
/*load the script*/
luaL_dofile(L, "first.lua");
/*cleanup Lua*/
lua_close(L);
return 0;
}
在lua.h里有这样的定义:typedef int (*lua_CFunction) (lua_State *L);所以lua_State * 的类型就是int (*lua_CFunction)
编译
gcc -o first first.c -I/usr/include/lua5.1 -llua5.1
(-I和-l要正确指定,否则编译出错)
执行
wss@localhost:~/lua/train/test_01$ ./first
lua program
4.lua调用c(有两种方式)
(1)c作为lua的一部分
/-----lua_call_c.c-----/
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
static int l_plus(lua_State* L)
{
lua_Integer a = luaL_checkinteger(L, 1);
lua_Integer b = luaL_checkinteger(L, 2);
lua_pushinteger(L, a+b);
return 1;
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction(L, l_plus);
lua_setglobal(L, "myplus");
if (luaL_dostring(L, "print(myplus(2,2))")) {
lua_close(L);
error("Failed to invoke");
}
lua_close(L);
return 0;
}
#>gcc -o lua_call_c lua_call_c.c -I/usr/include/lua5.1 -llua5.1
#>./lua_call_c
4
(2)c函数以库的形式被lua调用
/***mytestlib.c**/
#include <stdio.h>
#include <string.h>
#include<lua.h>
#include <lauxlib.h>
#include <lualib.h>
int add(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
int sub(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
int myprint(lua_State* L)
{
lua_pushstring(L,"lua call c");
return 1;
}
static luaL_Reg mylibs[] = {
{"add", add},
{"sub", sub},
{"myprint",myprint},
{NULL, NULL}
};
int luaopen_mytestlib(lua_State* L)
{
const char* libName = "mytestlib";
luaL_register(L,libName,mylibs);
return 1;
}
编译生成.so 库
gcc -fpic -shared -o mytestlib.so mytestlib.c
编写test.lua测试脚本,在test.lua里面调用mytestlib.so库
/*******test.lua***********/
require "mytestlib"
print(mytestlib.myprint())
print(mytestlib.add(1.0,23.0))
print(mytestlib.sub(20.1,19))
lua里调用c函数库时,需要以包名.函数名的形式进行调用
wss@localhost:~/lua/train/lua-call_c/2$ lua test.lua
lua call c
24
1.1
lua 与 c 的相互调用的更多相关文章
- C程序与Lua脚本相互调用
Lua脚本是一种可用于C程序开发/测试的工具,本篇介绍一下C程序与Lua脚本如何进行相互调用,更加详细的操作参见<Programing in Lua>.本文分为3个部分:1.Windows ...
- lua语言自学知识点----Lua与.Net相互调用
知识点: LuaInterface作用是用来完成Lua与C#的相互调用. LuaInterface核心库:1.luainterface.dll 用于C#读取lua(放在bin目录同级) 2.luane ...
- Lua 与 OC 相互调用
本文主要讲如何完成lua和object-c的相互调用. lua是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...
- lua编程之lua与C相互调用
lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情 ...
- Lua与C++相互调用
{--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...
- uLua学习笔记(三):Unity3D和Lua之间的相互调用
这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方 ...
- Unity3D 预备知识:C#与Lua相互调用
在使用Unity开发游戏以支持热更新的方案中,使用ULua是比较成熟的一种方案.那么,在使用ULua之前,我们必须先搞清楚,C#与Lua是怎样交互的了? 简单地说,c#调用lua, 是c# 通过Pin ...
- C#与lua相互调用
Lua是一种很好的扩展性语言,Lua解释器被设计成一个很容易嵌入到宿主程序的库.LuaInterface则用于实现Lua和CLR的混合编程. (一)C#调用Lua 测试环境:在VS2015中建一个C# ...
- 原生实现C#和Lua相互调用-Unity3D可用
引言 本篇简单介绍如何在C#中执行Lua脚本,传递数据到Lua中使用,以及Lua中调用C#导出的方法等.在Unity中开发测试,并打IL2CPP的Android包在模拟器上运行通过.Lua版本 ...
随机推荐
- PAT (Advanced Level) 1038. Recover the Smallest Number (30)
注意前导零的消去. #include <iostream> #include <string> #include <sstream> #include <al ...
- 动态规划: HDU 1789Doing Homework again
Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of h ...
- 搭建Spring+mybatis报错
java.lang.ClassCastException: com.sun.proxy.$Proxy12 cannot be cast to com.bdqn.service.impl.UserSer ...
- Meteor Blaze
Blaze是Meteor 软件包用于构建现场反应模板. Render方法 这种方法被用于绘制模板到DOM.首先,我们将创建 myNewTemplate 之后渲染. 我们增加 myContainer 这 ...
- android多个fragment返回键层层返回
在FragmentActivity的fragment跳转的时候加入到执行栈. public void switchFrag(BaseFragment to) { getSupportFragmentM ...
- Office EXCEL 如何保留两位小数,四舍五入
选中若干单元格,然后右击设置单元格格式,数值中保留两位小数 使用round函数四舍五入,如下图所示,我在N10单元格中输入"ROUND(M10,1)"即可,其中ROUND是函数 ...
- js 计算两个日期之间 相差几年几月几日
1.计算日期差 Mine.vue <!-- 我的 --> <template> <div> <!-- 标题栏 --> <x-header :lef ...
- 【剑指Offer】俯视50题之21 - 30题
面试题21包括min函数的栈 面试题22栈的压入.弹出序列 面试题23从上往下打印二叉树 面试题24二叉搜索树的后序遍历序列 面试题25二叉树中和为某一值的路径 面试题26复杂链表的复制 ...
- HDU1542Atlantis(扫描线)
HDU1542Atlantis(扫描线) 题目链接 题目大意:给你n个覆盖矩形,问最后覆盖的面积. 解题思路:将每一个矩形拆成两条线段,一条是+1的,还有一条是减1的.然后扫描先从上往下扫描,碰到加1 ...
- Python遇到的零碎小问题
切记else语句的后面直接加冒号: 字符和数字绝对不能直接相加 对于字符与整数之间的转化 ord('E')可以将其转化为45,chr(65)可以将其转化为A 编写程序的时候尽量要考虑时间复杂度 app ...