lua C API(2) - C 调用 Lua

2018-08-31 14:16:47

Lua 可以作为程序库用来扩展应用的功能。同时,Lua 程序中可以注册有其他语言实现的函数,这些函数可能由C语言(或其他语言)实现,可以增加一些不容易由 Lua 实现的功能。这使得 Lua 是可扩展的。对应的C和Lua中间有两种交互方式。

第一种,C作为应用程序语言,Lua 作为一个库使用,也就是所谓的 C 调用 Lua。

第二种,反过来,Lua 作为程序语言,C 作为库使用,即 Lua 调用 C。

这两种方式,C语言都使用相同的 API 与 Lua 通信,因此 C 和 Lua 交互这部分称为C API。

lua 和 c 交互是通过虚拟栈进行的,栈开始的索引为1,第一个压入栈的索引为1,第二个压入栈的索引为2,也可以反过来访问,-1代表栈顶元素。

栈的使用解决了C和LUA之间两个不协调的问题:

1.Lua使用自动垃圾收集机制,而C要求显式的分配和释放内存。
2.Lua使用动态数据类型(运行期间才做数据类型检查),而C使用静态类型(编译期间就得确定);

第一个例子

#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

int main (void) {
    char buff[256];
    int error;
    lua_State *L = luaL_newstate(); //打开lua
    luaL_openlibs(L); //打开标准库
    while (fgets(buff, sizeof(buff), stdin) != NULL) {
        //加载并运行代码
        error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
        lua_pcall(L, 0, 0, 0);

        if (error) {
            fprintf(stderr, "%s", lua_tostring(L, -1));
            lua_pop(L, 1); /* pop error message from the stack */
        }
    }

    lua_close(L);
    return 0;
}

读取设置全局变量

--main.lua
w=200
h=400
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

void main(){
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    //加载并执行代码
    if (luaL_loadfile(L, "main.lua") || lua_pcall(L, 0, 0, 0)){
        //如果失败,栈顶为错误信息
        printf("loadfile failed! %s\n", lua_tostring(L, -1));
    }
    
    //分别获取全局变量w,h的值并压入栈顶
    lua_getglobal(L, "w");
    lua_getglobal(L, "h");
    
    int w = lua_tointeger(L, -2); //获取栈顶下面的元素
    int h = lua_tointeger(L, -1); //获取栈顶元素
    printf("w=%d,h=%d\n", w, h);  //w=200,h=400
    
    //设置全局变量
    lua_pushinteger(L, 10);
    lua_setglobal(L, "w");
    
    //重新获取全局变量
    lua_getglobal(L, "w");
    lua_getglobal(L, "h");
    w = lua_tointeger(L, -2); //获取栈顶下面的元素
    h = lua_tointeger(L, -1); //获取栈顶元素
    printf("w=%d,h=%d\n", w, h);  //w=10,h=400
}

解析设置表格

--main.lua
tb = {name="freecls",url="www.freecls.com"}
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

void main(){
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    //加载并执行代码
    if (luaL_loadfile(L, "main.lua") || lua_pcall(L, 0, 0, 0)){
        //如果失败,栈顶为错误信息
        printf("loadfile failed! %s\n", lua_tostring(L, -1));
    }
    
    //获取全局变量表格tb的值并压入栈顶
    lua_getglobal(L, "tb");
    
    lua_pushstring(L, "name"); //压入键名
    //把栈顶当做key,栈-2处元素当做表格 的值(tb["name"])压入栈顶
    //该操作会把key弹出
    lua_gettable(L, -2);
    const char *name = lua_tostring(L, -1);
    
    lua_pop(L,1);  //弹出栈顶的值
    
    lua_pushstring(L, "url"); //压入键名
    lua_gettable(L, -2);
    const char *url = lua_tostring(L, -1);
    
    //name=freecls,url=www.freecls.com
    printf("name=%s,url=%s\n", name, url);
    
    //改变表格的值
    lua_pop(L,1);  //弹出栈顶的值
    lua_pushstring(L, "url"); //压入键名
    lua_pushstring(L, "http://www.freecls.com"); //压入值
    lua_settable(L, -3); //设置值并弹出2个元素
    
    //重新获取表格的值
    lua_pushstring(L, "url"); //压入键名
    lua_gettable(L, -2);
    url = lua_tostring(L, -1);
    
    //name=freecls,url=http://www.freecls.com
    printf("name=%s,url=%s\n", name, url);
}

调用lua函数

/main.lua
function foo(x,y)
    b = x+y
    
    return 1,b
end
//main.c
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

void main(){
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    //加载并执行代码
    if (luaL_loadfile(L, "main.lua") || lua_pcall(L, 0, 0, 0)){
        //如果失败,栈顶为错误信息
        printf("loadfile failed! %s\n", lua_tostring(L, -1));
    }
    
    //获取全局变量并压入栈顶
    lua_getglobal(L, "foo");
    
    //压入2个参数
    lua_pushinteger(L, 2);
    lua_pushinteger(L, 3);
    
    //调用函数,2个传入参数,2个返回参数
    //调用完后弹出3个元素
    if (lua_pcall(L, 2, 2, 0) != 0){
        printf("error running function ’f’: %s",lua_tostring(L, -1));
        return;
    }
    //如果调用成功,2个返回结果压入栈
    
    int a = lua_tointeger(L, -2);  //获取第1个返回值
    int b = lua_tointeger(L, -1);  //获取第2个返回值
    
    printf("%d,%d\n", a, b);  //5,1
}


备注:

1.本文只是对模块加载机制做简单的介绍,如果有疑问可以给我留言
2.lua的版本为5.1,运行环境centos7 64位
3.原文地址http://www.freecls.com/a/2712/101


©著作权归作者所有
收藏
推荐阅读
  • lua C API(1) - 函数汇总

    在调用C API时有几个重要的头文件:lua.h:基础函数库,lua_ 前缀。lauxlib.h辅助库,luaL_ 前缀,利用 lua.h 实现的更高层的抽象。lualib.h为了保持Lua的苗条,所...

  • lua模块安装

    lua模块安装可以利用 luarocks 命令,在centos7 上执行以下来安装。yum install epel-release yum install luarocks此时我们安装模块的的时候可...

  • lua coroutine(协程)

    协程相关的文章网上有很多,众说纷坛,相比其他技术概念理解起来没那么直接。因为协程涉及了很多底层高并发概念,没接触过操作系统调度,C语言等底层知识根本不可能完全理解。备注:以下我说的单进程就是指一个进程...

  • lua模拟面向对象编程

    lua中跟对象和类最像的就是表格有方法和属性,所以类和对象都只能用表格来模拟声明一下,其实表格的功能已经能应付大部分场景了,而且lua脚本语言本就不是面向对象语言(它的优势是轻量级简单快速),硬要模拟...

  • lua元表

    lua元表其实就是为了扩展表格间的运算,比如之前我们如果让2个表格相加就会报错,一旦我们设置了元表并加上了__add属性,那么就会正常执行。先看2个元表相关的函数setmetatable(table,...

  • nginx模块 ngx_http_headers_module

    ngx_http_headers_module 模块是用来增加 Expires 和 Cache-control,或者是任意的响应头。Syntax: add_header name value [alw...

  • nginx模块 ngx_http_gunzip_module、ngx_http_gzip_module、ngx_http_gzip_static_module

    ngx_http_gunzip_module 模块将文件解压缩后并在响应头加上 "Content-Encoding: gzip" 返回给客户端。为了解决客户端不支持gzip压缩。编译的时候带上 --w...

  • nginx模块 ngx_http_flv_module、ngx_http_mp4_module

    ngx_http_flv_module模块提供了对 flv 视频的伪流支持。编译的时候带上 --with-http_flv_module。它会根据指定的 start 参数来指定跳过多少字节,并在返回数...

  • nginx模块 ngx_http_fastcgi_module

    ngx_http_fastcgi_module 模块使得nginx可以与 fastcgi 服务器通信。比如目前要使得 nginx 支持 php 就得使用 fastcgi技术,在服务器上装上 nginx...

  • nginx模块 ngx_http_autoindex_module

    ngx_http_autoindex_module 模块可以将uri以 / 结尾时,列出里面的文件和目录。Syntax: autoindex on | off; Default: autoindex ...

简介
天降大任于斯人也,必先苦其心志。