Lua和C语言的交互——C API
Lua可作为扩展性语言(Lua可以作为程序库用来扩展应用的功能),同时也是个可扩展的语言(Lua程序中可以注册由其他语言实现的函数)。
C和Lua交互的部分称为C API。C API是一个C代码与Lua进行交互的函数集。他由以下部分组成:读写Lua全局变量的函数、调用Lua函数的函数、运行Lua代码片断的函数、注册C函数然后可以在Lua中被调用的函数,等等。
API中有些函数为了方便以宏的方式实现。
当在Lua和C之间交换数据时我们面临着两个问题:动态与静态类型系统的不匹配和自动与手动内存管理的不一致。解决办法是在C和Lua之间通信关键在于一个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。因为栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用。
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):从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作。
下面来看一段Lua和C++简单交互的代码:
#include <stdio.h>
#include <string.h> extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
} int main (void)
{
char buff[];
int error;
lua_State *L = lua_open(); /* opens Lua */
luaL_openlibs(L); while (fgets(buff, sizeof(buff), stdin) != NULL)
{
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || lua_pcall(L, , , );
if (error)
{
fprintf(stderr, "%s", lua_tostring(L, -));
lua_pop(L, );/* pop error message from the stack */
}
} lua_close(L);
return ;
}
上述代码在VS2010中正常运行,Lua使用5.1的版本,其中有几点需要注意的:
(1)lua5.0之前初始化库的用法如下:
luaopen_base(L); /* opens the basic library */ luaopen_table(L); /* opens the table library */ luaopen_io(L); /* opens the I/O library */ luaopen_string(L); /* opens the string lib. */ luaopen_math(L); /* opens the math lib. */
但5.0之后只需要一句话即可:
luaL_openlibs(L);
(2)需要添加依赖库:lua5.1.lib lua51.lib。
下面这个例子可以有助于加深对C和Lua之间堆栈的理解:
// 从栈底到栈顶依次遍历整个堆栈
static void stackDump(lua_State* L)
{
int i;
int top = lua_gettop(L);
for(i = ; i <= top; ++i)
{
int t = lua_type(L, i);
switch(t)
{
case LUA_TSTRING:
printf("'%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true": "false");
break;
case LUA_TNUMBER:
printf("'%g'", lua_tonumber(L, i));
break;
default:
printf("'%s'", lua_typename(L, t));
break;
}
printf(" ");
}
printf("\n");
} int main(void)
{
lua_State* L = lua_open();
luaL_openlibs(L); lua_pushboolean(L, );
lua_pushnumber(L, );
lua_pushnil(L);
lua_pushstring(L, "hello");
stackDump(L); lua_pushvalue(L, -);
stackDump(L); lua_replace(L, );
stackDump(L); lua_settop(L, );
stackDump(L); lua_remove(L, -);
stackDump(L); lua_settop(L, -);
stackDump(L); return ;
}
注意lua_replace首先会弹出栈顶元素,并且需要注意的是lua_replace(L, -1);语句会导致站顶元素弹出,其他元素不变。
作为配置语言是LUA的一个重要应用,下面看一个简单的这方面的例子。有一个含有简单字段记录的lua文件如下:
width =
height =
对该lua文件的解析大妈如下:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
} void error(lua_State* L, const char* fmt, ...)
{
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
lua_close(L);
exit(EXIT_FAILURE);
} void load(char* filename, int* width, int* height)
{
lua_State* L = lua_open();
luaL_openlibs(L); if(luaL_loadfile(L, filename) || lua_pcall(L, , , ))
{
error(L, "cannot run configuration file: %s", lua_tostring(L, -));
} lua_getglobal(L, "width");
lua_getglobal(L, "height"); if(!lua_isnumber(L, -))
error(L, "'width' should be a number\n"); if(!lua_isnumber(L, -))
error(L, "'height' should be a number\n"); *width = (int)lua_tonumber(L, -);
*height = (int)lua_tonumber(L, -); lua_close(L);
} int main(void)
{
int width, height;
load("c:\\luatest\\cfg.lua", &width, &height);
printf("width = %d height = %d \n", width, height);
return ;
}
Lua和C语言的交互——C API的更多相关文章
- C++操作Kafka使用Protobuf进行跨语言数据交互
C++操作Kafka使用Protobuf进行跨语言数据交互 Kafka 是一种分布式的,基于发布 / 订阅的消息系统.主要设计目标如下: 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 T ...
- Linux 下 expect 脚本语言中交互处理常用命令
Linux 下 expect 脚本语言中交互处理常用命令 1. #!/usr/bin/expect 告诉操作系统脚本里的代码使用那一个 shell 来执行.这里的 expect 其实和 Linux 下 ...
- 利用R语言进行交互数据可视化(转)
上周在中国R语言大会北京会场上,给大家分享了如何利用R语言交互数据可视化.现场同学对这块内容颇有兴趣,故今天把一些常用的交互可视化的R包搬出来与大家分享. rCharts包 说起R语言的交互包,第一个 ...
- Go语言使用百度翻译api
Go语言使用百度翻译api 之前做过一个使用百度翻译api的工具,这个工具用于用户的自动翻译功能,是使用C#调用百度翻译api接口,既然在学习Go语言,那必然也是要使用Go来玩耍一番.这里我是这么安排 ...
- atitit.跨语言执行cmd cli api的原理及兼容性设计草案
atitit.跨语言执行cmd cli api的原理及兼容性设计草案 1. 标准输入,标准输出,标准错误与重新定向1 2. 常见问题2 2.1. 执行bat文件2 2.2. 执行bat文件 /c ...
- Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结
Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结 1.1. 要兼容的重要语言api1 1.2. 常用基础api分类 core api1 1.3. 比较常用的扩展库 ...
- Atitit.跨语言系统服务管理器api兼容设计
Atitit.跨语言系统服务管理器api兼容设计 1. Common api,兼容sc ,service control??1 1.1. 服务创建,use sc1 1.2. 服务delete ,use ...
- Lua和C之间的交互
转自:http://blog.csdn.net/sumoyu/article/details/2592693 (一) Lua 调C函数 什么样类型的函数可以被Lua调用 typedef int ( ...
- Lua游戏脚本语言入门(一)
作者: 沐枫 (第二人生成员) 原文地址:http://job.17173.com/content/2009-01-22/20090122143452606,1.shtml 在这篇文章中,我想向大家介 ...
随机推荐
- MYSQL操作数据表中的记录
36:操作数据表中的记录插入记录 INSERT INTO 表名 VALUES(); 或者INSERT 表名 VALUES(); UPDATE更新记录(单表更新) DELETE删除记录( ...
- asp.net mvc通过预处理实现数据过滤和数据篡改。
需求特别简单.在 Controller加过滤器.实现在所有的方法上增加id=12312321312.另外将price篡改为price+5. 这样做可以最大的减少代码的改动量,人员变动厉害,业务也模糊了 ...
- phpweb成品网站最新版(注入、上传、写shell)
注入:之所以鸡肋就是该漏洞利用安装文件 重新生成 配置文件 写入可执行代码 鸡肋1: 具有破坏性 动作非常大 重新写了配置文件 数据库连接文件鸡肋2: 有一定安全常识的站长都会删掉 install 目 ...
- 我所理解的JavaScript闭包
目录 一.闭包(Closure) 1.1.什么是闭包? 1.2.为什么要用闭包(作用)? 1.2.1.保护函数内的变量安全. 1.2.2.通过访问外部变量,一个闭包可以暂时保存这些变量的上下文环境,当 ...
- Advacned Puppet: Puppet Master性能调优
本文是Advanced Puppet系列的第一篇:Puppet master性能调优,谈一谈如何优化和提高C/S架构下master端的性能. 故事情节往往惊人地类似:你是一名使用Puppet管理线上业 ...
- mycat服务启动{管理模块启动过程}
mycat启动的时候启动了三个模块 1:NIOConnector(负责链接mysql数据库,连接池以数据库为准不以链接字符串为准), 1:NIOAcceptor,ManagerConnectionFa ...
- Base: 一种 Acid 的替代方案
原文链接: BASE: An Acid Alternative Pdf下载链接: Base 数据库 ACID,都不陌生:原子性.一致性.隔离性和持久性,这在单台服务器就能搞定的时代,很容易实现,但是到 ...
- Mac OS 中设置VPN(pptp连接方式)
第一步:点击系统设置(如图) 第二步:点击网络,进入网络设置(如图) 第三步:点击+号-创建新服务,创建新的VPN网络连接(如图) 第四步:接口-中选-VPN, VPN类型-中选-PPTP,服务名称- ...
- 将树苺派升级到Raspbian 8 (Jessie)
我的树苺派2B跑的是Raspbian 7 (Wheezy),有不少软件都让我觉察出老旧来.想着Debian官方已经发布Debian 8 (Jessie)大半年了(8.0发布于2015/04/25),树 ...
- Mac OS X下Sublime Text (V2.0.1)破解
转自:http://blog.sina.com.cn/s/blog_559d66460101cab0.html 1. 在http://www.sublimetext.com/上根据操作系统选择对应版本 ...