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的更多相关文章

  1. C++操作Kafka使用Protobuf进行跨语言数据交互

    C++操作Kafka使用Protobuf进行跨语言数据交互 Kafka 是一种分布式的,基于发布 / 订阅的消息系统.主要设计目标如下: 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 T ...

  2. Linux 下 expect 脚本语言中交互处理常用命令

    Linux 下 expect 脚本语言中交互处理常用命令 1. #!/usr/bin/expect 告诉操作系统脚本里的代码使用那一个 shell 来执行.这里的 expect 其实和 Linux 下 ...

  3. 利用R语言进行交互数据可视化(转)

    上周在中国R语言大会北京会场上,给大家分享了如何利用R语言交互数据可视化.现场同学对这块内容颇有兴趣,故今天把一些常用的交互可视化的R包搬出来与大家分享. rCharts包 说起R语言的交互包,第一个 ...

  4. Go语言使用百度翻译api

    Go语言使用百度翻译api 之前做过一个使用百度翻译api的工具,这个工具用于用户的自动翻译功能,是使用C#调用百度翻译api接口,既然在学习Go语言,那必然也是要使用Go来玩耍一番.这里我是这么安排 ...

  5. atitit.跨语言执行cmd cli api的原理及兼容性设计草案

    atitit.跨语言执行cmd cli api的原理及兼容性设计草案 1. 标准输入,标准输出,标准错误与重新定向1 2. 常见问题2 2.1. 执行bat文件2 2.2. 执行bat文件  /c   ...

  6. Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结

    Atitit.常用语言的常用内部api 以及API兼容性对源码级别可移植的重要性 总结 1.1. 要兼容的重要语言api1 1.2. 常用基础api分类 core api1 1.3. 比较常用的扩展库 ...

  7. Atitit.跨语言系统服务管理器api兼容设计

    Atitit.跨语言系统服务管理器api兼容设计 1. Common api,兼容sc ,service control??1 1.1. 服务创建,use sc1 1.2. 服务delete ,use ...

  8. Lua和C之间的交互

    转自:http://blog.csdn.net/sumoyu/article/details/2592693 (一) Lua 调C函数 什么样类型的函数可以被Lua调用   typedef int ( ...

  9. Lua游戏脚本语言入门(一)

    作者: 沐枫 (第二人生成员) 原文地址:http://job.17173.com/content/2009-01-22/20090122143452606,1.shtml 在这篇文章中,我想向大家介 ...

随机推荐

  1. javaweb学习总结(二十一)——JavaWeb的两种开发模式

    SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...

  2. 出现Bad command or the file name的原因

    出现Bad command or file name的原因 中文释义:错误的命令或文件名 . 错误原因:不能识别输入的命令 . 方法:检查所输入的指令是否正确,包括拼写和大小写等情况.

  3. Android MonoGame坑记

    1.Content 加载声音API错误: 2.TouchPanel.GetState()属于抢占式的,用一次后面不能继续使用,否则状态尚属第一次: 3.TouchPanel 坐标来自于硬件本身: 4. ...

  4. MAT(Memory Analyzer Tool)工具入门介绍(转)

    1.MAT是什么? MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速.功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗 ...

  5. NEWS - InstallShield 2015 正式发布

    如果您需要为Windows®应用程序创建安装,InstallShield®便是您的最佳解决方案.在为桌面.服务器.云.Web和虚拟环境构建可靠的Windows Installer (MSI)和Inst ...

  6. React中props.children和React.Children的区别

    在React中,当涉及组件嵌套,在父组件中使用props.children把所有子组件显示出来.如下: function ParentComponent(props){ return ( <di ...

  7. Android中解决图像解码导致的OOM问题

    Android中解决图像解码导致的OOM问题 原文链接:http://blog.csdn.net/zjl5211314/article/details/7042017

  8. Javascript 严格模式

    简介 严格模式是一种将更好的错误检查引入代码中的方法. 在使用严格模式时,你无法使用隐式声明的变量.将值赋给只读属性或将属性添加到不可扩展的对象等. 声明严格模式 可以通过在文件.程序或函数的开头添加 ...

  9. python报错:SyntaxError: Non-ASCII character '\xe5'的解决方法

    最近在学习机器学习,上面的代码都是一些python代码,对于python只是会一些基础性的东西,刚才就遇到了一个比较low的问题,但是还是记录一下吧. 在python代码中出现了中文,但是我又把# - ...

  10. uestc_retarded 模板

    虽然这个队,以后再也没有了,但是他的模板,是永垂不朽的![误 #include <ext/pb_ds/priority_queue.hpp> __gnu_pbds::priority_qu ...