Lua C接口编程(二)

简介: Lua C接口编程(二)

引言

上篇文章我们学习了C如何调用Lua,今天我们就来聊聊Lua 如何调用C。

Lua版本:Lua 5.3.5

对于Lua提供的接口有不清楚的,可以参考Lua接口官方文档

一、Lua调用C步骤

  1. 需要将C文件编译成动态库
  2. 在Lua文件中使用package.cpath配置C动态库路径
  3. 使用require 关键字引入指定C文件

因为Lua只认识.so文件,会去识别以 luaopen_* 开头的函数执行。

二、代码示例

2.1 lua 通过调用C中的方法将自己参数打印到终端

Lua源文件 test-tbl.lua

package.cpath = "./?.so" --c库的路径
local so = require "tbl.c"  -- 这里xxx.c  对应 xxx.so 动态库
so.echo("hello world") -- 新的虚拟栈
so.echo("hello world1")-- 新的虚拟栈
so.echo("hello world2")-- 新的虚拟栈

C源文件 lua-tbl.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
static int
lecho (lua_State *L) {
    const char* str = lua_tostring(L, -1);
    fprintf(stdout, "%s\n", str);
    return 0;
}
static const luaL_Reg l[] = {// 导出给lua使用数组
  {"echo", lecho},
  {NULL, NULL},
};
int
luaopen_tbl_c(lua_State *L) { // local tbl = require "tbl.c"
    // 创建一张新的表,并预分配足够保存下数组 l 内容的空间
    luaL_newlib(L, l);
  return 1;
}

编译 lua-tbl.c 文件为动态库

gcc  lua-tbl.c -fPIC -shared -o  tbl.so -Wall

就会在当前目录会生成 tbl.so 文件,执行 lua test-tbl.lua

运行结果:

2.2 userdata 实战应用

Lua源文件 test-ud.lua

package.cpath = "./?.so"
local so = require "ud.c"
local ud = so.new()
ud:echo("hello world1")
ud:again()
ud:echo("hello world2")
ud:again()
ud:echo("hello world3")
ud:again()
--./lua/src/lua test-ud.lua

C源文件 lua-ud.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct log {
    int count;
};
static int
lagain(lua_State *L) {
    struct log *p = (struct log *)luaL_checkudata(L, 1, "mk.ud.log");
    lua_getuservalue(L, -1);
    const char* str = lua_tostring(L, -1);
    fprintf(stdout, "ud[n=%d]----%s\n", p->count, str);
    return 0;
}
static int
lecho(lua_State *L) {
    /*
        void *luaL_checkudata (lua_State *L, int arg, const char *tname);
        检查arg是不是userdata类型,如果是 返回userdata的内存地址
    */
    struct log *p = (struct log *)luaL_checkudata(L, 1, "mk.ud.log");
    const char* str = lua_tostring(L, -1);
    p->count++;
    // Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. Returns 0 if the userdata does not have that value.
    lua_setuservalue(L, -2);
    fprintf(stdout, "ud[n=%d]----%s\n", p->count, str);
  return 0;
}
static int
lnew (lua_State *L) {
    struct log *q = (struct log*)lua_newuserdata(L, sizeof(struct log));
    q->count = 0;
    lua_pushstring(L, "");
    lua_setuservalue(L, -2);
    // 如果key(mk.ud.log) 存在,返回0; 否则为userdata创建一个新表table,插入__name = mk.ud.log, 为注册表添加 [mk.ud.log] = table 返回1
  if (luaL_newmetatable(L, "mk.ud.log")) {
        luaL_Reg m[] = {
      {"echo", lecho},
            {"again", lagain},
      {NULL, NULL},
    };
    luaL_newlib(L, m);
    lua_setfield(L, -2, "__index"); // LUA_REGISTRYINDEX[__index] = stackTopElem
        // int lua_setmetatable (lua_State *L, int index);
        // Pops a table or nil from the stack and sets that value as the new metatable for the value at the given index.
        // 从栈顶弹出一个table或者nil, 将该值设置为给定索引index的新元表
        lua_setmetatable(L, -2);
    }
    return 1;
}
static const luaL_Reg l[] = {
  {"new", lnew},
  {NULL, NULL},
};
int
luaopen_ud_c(lua_State *L) {
    luaL_newlib(L, l);
  return 1;
}

编译 lua-ud.c 文件为动态库:

gcc  lua-ud.c -fPIC -shared -o  ud.so -Wall

就会在当前目录会生成 ud.so 文件,执行 lua test-ud.lua

运行结果:

2.3 upvalue上值实战应用

Lua源文件 test-uv.lua

package.cpath = "./?.so"
local so = require "uv.c"
so.echo("hello world1")
so.echo("hello world2")
so.echo("hello world3")

C源文件 lua-uv.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>
// 闭包实现:  函数 + 上值  luaL_setfuncs
/*
    int lua_upvalueindex (int i);
    函数返回一个伪索引,这个伪索引是 i位置表示的上值   i 的范围 [1, 256]
    Returns the pseudo-index that represents the i-th upvalue of the running function (see §4.2). i must be in the range [1,256].
*/
// lua_upvalueindex(1)
// lua_upvalueindex(2)
static int
lecho (lua_State *L) {
  lua_Integer n = lua_tointeger(L, lua_upvalueindex(1));
    n++;
    const char* str = lua_tostring(L, -1);
    fprintf(stdout, "[n=%lld]---%s\n", n, str);
    lua_pushinteger(L, n);
    lua_replace(L, lua_upvalueindex(1));
    return 0;
}
static const luaL_Reg l[] = {
  {"echo", lecho},
  {NULL, NULL},   // 必须以{NULL, NULL},结尾
};
int
luaopen_uv_c(lua_State *L) { // local tbl = require "tbl.c"
  luaL_newlibtable(L, l);// 1
    lua_pushinteger(L, 0);// 2
    /*
        void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
        将l数组中所有的function 注册到栈顶的table中
        当 nup 不为零时,所有函数都使用 nup up值创建,并使用先前推送到库表顶部堆栈上的 nup 值的副本进行初始化
    */
  luaL_setfuncs(L, l, 1);// 上值
    // luaL_newlib(L, l);
  return 1;
}

编译 lua-uv.c 文件为动态库:

gcc  lua-uv.c -fPIC -shared -o  uv.so -Wall

就会在当前目录会生成 uv.so 文件,执行 lua test-uv.lua

运行结果:


推荐一个零声学院免费教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习:

相关文章
|
2月前
|
算法 NoSQL Java
springboot整合redis及lua脚本实现接口限流
springboot整合redis及lua脚本实现接口限流
76 0
|
3月前
|
存储 API C语言
Lua C接口编程(一)
Lua C接口编程(一)
|
6月前
|
算法 NoSQL Java
分布式接口幂等性、分布式限流(Guava 、nginx和lua限流)
接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条,这就没有保证接口的幂等性。
|
6月前
|
编译器 Linux C语言
lua编程基础
lua编程基础
51 0
|
7月前
|
JSON 数据格式
wrk post lua脚本取excel参数压力测试,判断接口性能
wrk post lua脚本取excel参数压力测试,判断接口性能
140 0
|
NoSQL 应用服务中间件 API
【精选】Nginx模块Lua-Nginx-Module学习笔记(一)Nginx Lua API 接口详解
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis 一、介绍   各种* _by_lua,* _by_lua_block和* _by_lua_file配置指令用作nginx.conf文件中Lua API的网关。
2326 0
|
索引 C# 程序员
Lua下通过元表模拟OOP编程,继承多态
Lua本身是没有以明确的定义来支持OOP编程的,但是我们却可以通过Lua内核提供的一些特性来间接实现简单的面向对象的编程。  通过Lua中的 table结构  metatable 以及函数可以配合实现OOP,以及继承。
1297 0