Lua —— 轻量小巧脚本语言,支持与C相互调用

Lua —— 轻量小巧脚本语言,支持与C相互调用

Lua 语言 logo

Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于 1993 年开发。

Lua 用标准 C 语言编写并开放源代码。

优势:

  • 轻量级:使用标准C语言编写,编译后仅仅100k+,可以很方便地加入嵌入式程序中。
  • 可扩展:Lua 提供非常易于使用的扩展接口和机制。由宿主语言(通常是 C、C++)提供功能,Lua 如同内置功能一样进行调用。
  • 支持面向过程编程和函数式编程
  • 自动内存管理。只提供一种通用类型的表(table),可以用来实现数组,哈希表,集合,对象等。
  • 提供多线程(协同进程)支持

但 Lua 目前没有提供强大的库,不适合作为开发独立应用程序的语言使用。

Lua 数据类型

数据类型 说明
nil 表示一个无效的值(类似于null、NULL、false等)
boolean 布尔型,true 或 false
number 双精度类型的实浮点数
string 字符串有一对双引号("")或单引号('')表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的 C 数据结构
thread 表示执行独立的线路,用于执行协同程序
table Lua 中的表(table)其实是一个 "关联数组"(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过 "构造表达式" 来完成,最简单构造表达式是 {},用来创建一个空表。

测试数据类型(使用 type ):


print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(2))                  --> number
print(type(3.14))               --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(nil)))          --> string

Lua 与 C 语言的交互

Lua 能与 C 语言交互是其最大的魅力之一。

运用 C 的库扩展了其强大的功能。

C 与 Lua 交互的部分称为 C API。C API 是一个 C 代码与 Lua 进行交互的函数集。主要组成部分为:

  • 读写 Lua 全局变量的函数
  • 调用 Lua 函数的函数
  • 运行 Lua 代码片段的函数
  • 注册 C 函数然后可以在 Lua 中被调用的函数

C 与 Lua 之间采用一个虚拟的栈进行通信,这样巧妙地解决了数据类型匹配问题和内存管理不一致的问题。

所有 C 与 Lua 之间的数据交换也都通过这个栈来完成。

Lua 以一个严格的 LIFO (后进先出)规则来操作栈。

1. C 调用 Lua

初始化和结束接口。


lua_State *L = lua_open();    // 创建 lua_State 堆栈(用于交换数据)。
luaL_openlibs(L);             // 初始化堆栈

...

lua_close(L);                 // 释放

C 与 Lua 的交互方式可以是通过 luaL_dostring (直接运行 Lua 代码)或 luaL_dofile (直接运行 Lua 文件)。

如 Lua 文件


// 文件名: test_lua.lua
print("This is Lua !")

可以执行:


// 可以直接执行代码
const char * buf = "print("This is Lua !")";
luaL_dostring(L, buf);

// 也可以直接执行文件
luaL_dofile(L, "test_lua.lua");

由于没有 include Lua 文件的机制。

如果需要访问 Lua 文件内的数据或接口,需要调用 luaL_loadfile 加载 Lua 文件,后续才能进行读取接口或数据。

下面以读取 test_lua.lua 文件为例:


int main()
{
    lua_State *L = lua_open();        // 创建 lua_State 堆栈(用于交换数据)。
    luaL_openlibs(L);                 // 初始化堆栈

    if(luaL_loadfile(L, filename))    // 返回 1 则加载出错
    {
        return -1;
    }
    
    ...

    lua_close(L);                     // 释放
    return 0;
}

调用 Lua 函数的方法

Lua 代码:


function add(a, b, c)
    local sum=a+b
    return sum,c
end

C 调用 Lua 函数:


lua_getglobal(L, "add");                      // 在Lua中,函数等同于变量,所以你可以这样来取得这个函数
lua_pushnumber(L, 100);                       // 将参数压栈,对应 a
lua_pushnumber(L, 20);                        // 将参数压栈,对应 b
lua_pushstring(L, "test add function");       // 将参数压栈,对应 c

lua_pcall(L, 3, 2, 0);                        // 调用函数,3个参数,2个返回值,错误处理函数(0表示没有,其它表示处理函数在栈的索引)。

const char * result1 = lua_tostring(L, -1);   // 返回值,对应返回的 c (按返回值入栈顺序,先是 sum, 后是 c, 所以 c 的顺序为 -1)
int result2 = lua_tonumber(L, -2);            // 返回值,对应返回的 sum

2. Lua 调用 C

C 函数:


int lua_strlen(lua_State *L)                    // Lua 用栈进行数据传递,所以参数用栈就可以了
{
    const char * ptr = lua_tostring(L, -1);     // 获取输入的第一个参数
    int len = strlen(ptr);                      // 计算字符串长度
    lua_pushnumber(L, len);                     // 计算结果入栈
    return 1;
}

int main()
{
    lua_State *L = lua_open();
    luaL_openlibs(L);

    ...

    lua_register(L, "lua_strlen", lua_strlen);  // 需要注册一下,声明暴露给 Lua 调用的接口和名称。

    ...

    lua_close(L);
    return 0;
}

Lua 调用文件:


function calc_length(s)
    local len=lua_strlen(s)
    return len
end

附录:C API 一些接口说明

接口 说明 部分参数说明
lua_State* lua_open(); 获取一个新的 Lua 状态机 如果内存不足返回 NULL
lua_State *lua_newstate (lua_Alloc f, void *ud); 获取一个新的 Lua 状态机
lua_State* lua_open(); 获取一个新的 Lua 状态机 参数 f 指定内存分配函数,参数 ud 是传给 f 函数的指针。如果内存不足返回 NULL
void lua_close(lua_State *L); 销毁 Lua 状态机所有对象,回收分配的内存
void luaL_openlibs(lua_State *L); 在给定的 Lua 状态机中打开所有的标准 Lua 库
int luaL_dofile(lua_State *L, char *lua_script); 加载并执行给定的 Lua 文件 成功返回 0,错误返回 1
int luaL_dostring (lua_State *L, const char *str); 加载并执行给定 string 成功返回 0,错误返回 1
int luaL_loadfile (lua_State *L, const char *filename); 从文件加载 chunk 成功返回 0,错误返回 1
int luaL_loadstring (lua_State *L, const char *s); 从字符串加载 chunk 成功返回 0,错误返回 1
void lua_pop(lua_State *L, int n); 从栈顶弹出 n 个元素
int lua_gettop (lua_State *L); 返回栈顶元素的索引(也即元素个数)
void lua_call (lua_State *L, int nargs, int nresults); 调用函数 参数 nargs 指定函数参数个数,参数 nresults 指定返回值个数。
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); 以保护模式调用函数,如果发生错误,捕捉它,并将错误消息压入栈,然后返回错误码。 参数 nargs 指定函数参数个数,参数 nresults 指定返回值个数,参数 errfunc 是错误处理函数在栈的索引(没有时为 0 )。
int lua_type (lua_State *L, int index); 返回第 index 个数据的类型ID 返回类型ID为:LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,674评论 0 38
  • 1. 写在前面 很多时候我们都需要借助一些脚本语言来为我们实现一些动态的配置,那么就会涉及到如何让脚本语言跟原生语...
    杰嗒嗒的阿杰阅读 3,418评论 9 31
  • 第一篇 语言 第0章 序言 Lua仅让你用少量的代码解决关键问题。 Lua所提供的机制是C不擅长的:高级语言,动态...
    testfor阅读 2,632评论 1 7
  • 名称 说明 docLua 相关的文档,包括了编译文档、接口文档等 Makefile 编译Lua使用,在...
    一川烟草i蓑衣阅读 1,403评论 0 1
  • (我想,你还是可以看看的,嗯……因为没有错别字……因为这是我仅剩的勇气,脸皮厚成我这样的也是可以了。让我最后不负责...
    于子禾阅读 199评论 0 0