C语言和Lua交互(一)

来源:互联网 发布:js自定义弹出框 编辑:程序博客网 时间:2024/05/16 04:12

  Lua可作为扩展性语言(Lua可以作为程序库用来扩展应用的功能),同时也是个可扩展的语言(Lua程序中可以注册由其他语言实现的函数)。
  Lua和C通信的主要方法是通过一个虚拟栈来完成,lua提供了C API对栈进行操作。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。
  C API是一个C代码与Lua进行交互的函数集。他由以下部分组成:读写Lua全局变量的函数、调用Lua函数的函数、运行Lua代码片断的函数、注册C函数然后可以在Lua中被调用的函数,等等。

  API用索引来访问栈中的元素,堆栈索引可以是正数也可以是负数。
  区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。
  栈
  
  Lua以一个严格的LIFO规则(后进先出;也就是说,始终存取栈顶)来操作栈: 
  (1)C调用Lua时,返回结果只会改变栈顶部分。
  (2)编写C代码比较自由,可以查询栈上的任何元素,在任何一个位置插入和删除元素。    

在调用C API时有几个重要的头文件,这几个头文件都是lua源代码,可以直接下载使用:
  (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环境中。

C API参考手册:http://www.lua.org/manual/5.3/
云风翻译中文手册:http://cloudwu.github.io/lua53doc/contents.html

常用辅助函数:

lua_State *luaL_newstate (void);//创建一个新环境(新的Lua状态)void luaL_openlibs (lua_State *L);//打开指定状态机中的所有 Lua 标准库。如:print,pcallint luaL_loadstring (lua_State *L, const char *s); //将一个字符串加载为  Lua  代码块。int luaL_loadfile (lua_State *L, const char *filename);//把一个文件加载为  Lua  代码块。 int luaL_loadfilex (lua_State *L, const char *filename,const char *mode);int luaL_loadbuffer (lua_State *L,const char *buff,size_t sz,const char *name);int luaL_loadbufferx (lua_State *L,const char *buff,size_t sz,const char *name,const char *mode);

常用的基础函数:

压入栈元素  

void lua_pushnil (lua_State *L);//将空值压栈。void lua_pushboolean (lua_State *L, int bool);void lua_pushnumber (lua_State *L, double n);//把一个值为 n 的浮点数压栈。void lua_pushlstring (lua_State *L, const char *s, size_t length);void lua_pushstring (lua_State *L, const char *s);//将指针  s 指向的零结尾的字符串压栈。 因此  s 处的内存在函数返回后,可以释放掉或是立刻重用于其它用途。 返回内部副本的指针。 

检查一个元素能否被转换成指定的类型。

  int lua_isnil (lua_State *L, int index);//当给定索引的值是 nil 时,返回 1 ,否则返回 0 。  int lua_isnumber (lua_State *L, int index);//当给定索引的值是一个数字,或是一个可转换为数字的字符串时,返回1,否则返回 0 。  int lua_isstring (lua_State *L, int index);//当给定索引的值是一个字符串或是一个数字  (数字总能转换成字符串)时,返回 1 ,否则返回 0 。  int lua_istable (lua_State *L, int index);//当给定索引的值是一张表时,返回 1 ,否则返回 0 。  int lua_isboolean (lua_State *L, int index);//当给定索引的值是一个布尔量时,返回 1 ,否则返回 0 。  int lua_isfunction (lua_State *L, int index);//当给定索引的值是一个函数( C 或 Lua 函数均可)时,返回 1 ,否则返回0 。

从栈中获得值。即使给定的元素类型不正确,调用这些函数也没问题。

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_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>#include "lua.h"#include "lauxlib.h"#include "lualib.h"int main(void){    char buff[256];    int error;    lua_State *L = luaL_newstate(); //打开Lua,创建一个新环境(新的Lua状态)    luaL_openlibs(L);   //打开标准库, 如: print, pcall    //接收用户输入lua代码, 并编译解析    while(fgets(buff,sizeof(buff),stdin)!=NULL){        error = luaL_loadbuffer(L,buff,strlen(buff),"line")||lua_pcall(L,0,0,0);//luaL_loadbuffer编译Lua代码(没有错误则压入栈),lua_pcall执行        if(error){            //执行或编译错误lua_tostring打印错误信息            fprintf(stderr,"%s\n",lua_tostring(L,-1));            lua_pop(L,1);   //从栈中弹出错误消息        }    }    lua_close(L);//关闭lua状态    return 0;}

编译代码

gcc -lm  -g -o testlua testlua.c /usr/local/lib/liblua.a -ldl

运行程序,输入lua代码
例如: print “aaaaa”

Lua和C++简单交互代码:

#include <iostream>#include <string.h>using namespace std;//告诉编译器要采用c编译的方式,而不是c++编译的方式。extern "C"{    #include "lua.h"    #include "lauxlib.h"    #include "lualib.h"}int main(void){    char buff[256];    int error;    lua_State *L = luaL_newstate(); //打开Lua,创建一个新环境(新的Lua状态)    luaL_openlibs(L);   //打开标准库, 如: print, pcall    //接收用户输入lua代码, 并编译解析    while(fgets(buff,sizeof(buff),stdin)!=NULL){        error = luaL_loadbuffer(L,buff,strlen(buff),"line")||lua_pcall(L,0,0,0);//luaL_loadbuffer编译Lua代码(没有错误则压入栈),lua_pcall执行        if(error){            //执行或编译错误lua_tostring打印错误信息            fprintf(stderr,"%s\n",lua_tostring(L,-1));            lua_pop(L,1);   //从栈中弹出错误消息        }    }    lua_close(L);//关闭lua状态    return 0;}

主要区别是extern “C”
由于lua源码是C编写的,所以需要告知编译器编译时使用C的方式编译,而不是C++的方式编译

编译代码:

g++ -lm  -g -o testlua1 testlua1.cpp /usr/local/lib/liblua.a -ldl

运行程序,输入lua代码
例如: print “aaaaa”

0 0
原创粉丝点击