C LUA 混合编程

前言

经常使用Python语言进行开发,充分感受到动态语言的优势,列表和字典等高级数据结构在这些动态语言里非常方便使用,但是在C语言里就被束缚住了,并且C的库也比较少,很多功能都需要另外找别人写的库,或者自己造轮子。

LUA

LUA作为一种嵌入式语言,很多优秀的软件都有集成它,比如nginx和redis和游戏引擎。LUA虽然是解释型语言,但它比其他解释型语言都快。

LUA语言一般用于业务控制,适用于经常变化的用户逻辑控制,核心功能仍然使用C编写。达到快速开发和解耦的目的。

lua 源文件

一个简单的lua源文件,包含2个函数

--
-- Created by IntelliJ IDEA.
-- User: yumm
-- Date: 2018/4/12
-- Time: 11:50
-- To change this template use File | Settings | File Templates.
--

function add (x, y)
    return x + y
end

function str_split(lines, c)
    return lines..c.."可以的"
end

函数封装

参照LUA 5.3 版本的手册,封装了一个调用LUA的函数。

void call_va(lua_State *L, const char *func, const char *sig, ...) {
    va_list vl;
    int narg, nres;  /* number of arguments and results */
    va_start(vl, sig);
    lua_getglobal(L, func);  /* push function */

    for (narg = 0; *sig; narg++) {  /* repeat for each argument */
        /* check stack space */
        luaL_checkstack(L, 1, "too many arguments");
        switch (*sig++) {
            case 'd':  /* double argument */
                lua_pushnumber(L, va_arg(vl, double));
                break;
            case 'i':  /* int argument */
                lua_pushinteger(L, va_arg(vl, int));
                break;
            case 's':  /* string argument */
                lua_pushstring(L, va_arg(vl, char *));
                break;
            case '>':  /* end of arguments */
                goto endargs;  /* break the loop */
            default:
                error(L, "invalid option (%c)\n", *(sig - 1));
        }
    }

    endargs:

    nres = strlen(sig);  /* number of expected results */
    if (lua_pcall(L, narg, nres, 0) != 0)  /* do the call */
        error(L, "error calling '%s': %s\n", func,
              lua_tostring(L, -1));

    nres = -nres;  /* stack index of first result */
    while (*sig) {  /* repeat for each result */
        switch (*sig++) {
            case 'd': {  /* double result */
                int isnum;
                double n = lua_tonumberx(L, nres, &isnum);
                if (!isnum)
                    error(L, "wrong result type\n");
                *va_arg(vl, double *) = n;
                break;
            }
            case 'i': {  /* int result */
                int isnum;
                int n = lua_tointegerx(L, nres, &isnum);
                if (!isnum)
                    error(L, "wrong result type\n");
                *va_arg(vl, int *) = n;
                break;
            }
            case 's': {  /* string result */
                const char *s = lua_tostring(L, nres);
                if (s == NULL)
                    error(L, "wrong result type\n");
                *va_arg(vl, const char **) = s;
                break;
            }
            default:
                error(L, "invalid option (%c)\n", *(sig - 1));
        }
        nres++; }

    va_end(vl);
}

调用方式为

call_va(L, "add", "ii>i", x, y, &z);
  1. L为lua对象
  2. add为lua 函数
  3. ii>i 为 参数格式,'>'隔开入参和出参,这个格式表示函数add有2个入参,都为整数。返回1个值,类型为整数。
  4. x, y, &z 为入参和出参,出参必须传址。

main函数

5.3 版本通过luaL_newstate()函数获取一个lua对象

int main(void) {

    lua_State *L = luaL_newstate();
    luaL_openlibs(L);        /* opens the standard libraries */

    int x = 3, y = 4, z;
    char *s1 = "this is test line", *s = " 不一定 and next line", *new_str;


    if (luaL_dofile(L, "../lua_fun.lua"))
        error(L, "cannot run config. file: %s\n", lua_tostring(L, -1));

    call_va(L, "add", "ii>i", x, y, &z);
    lua_pop(L, -1);
    printf("z is %d\n", z);

    call_va(L, "str_split", "ss>s", s1, s, &new_str);
    lua_pop(L, -1);

    printf("new str is %s\n", new_str);

    stackDump(L);

    lua_close(L);
    return 0;
}

C和LUA通讯机制

C和LUA通过一个虚拟栈进行数据交换。

  1. 当调用lua函数时,先获取lua文件中的函数(获取的结果会报错在栈中),然后依次压人参数。通过函数lua_pcall使lua发送函数调用。
  2. lua调用函数时,会将函数名和参数从栈中取出。运行函数,并将结果再压入栈中。如果调用出错,则会压入一条错误信息到栈中。
  3. lua_pcall返回后,需要通过函数lua_to从栈中获取返回值。lua_to函数不会将值从栈中弹出,需要通过函数lua_pop手动弹出返回值。
  4. 虚拟栈默认保存20个对象。

其余代码

头文件和辅助函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#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);
}

static void stackDump(lua_State *L) {
    int i;
    int top = lua_gettop(L);  /* depth of the stack */

    if (top == 0) {
        printf("<stack is emtpy>\n");
        return;
    }

    for (i = 1; i <= top; i++) {  /* repeat for each level */
        int t = lua_type(L, i);
        switch (t) {
            case LUA_TSTRING: {  /* strings */
                printf("'%s'", lua_tostring(L, i));
                break;
            }
            case LUA_TBOOLEAN: {  /* Booleans */
                printf(lua_toboolean(L, i) ? "true" : "false");
                break; }
            case LUA_TNUMBER: {  /* numbers */
                printf("%g", lua_tonumber(L, i));
                break;
            }
            default: {  /* other values */
                printf("%s", lua_typename(L, t));
                break; }
        }
        printf("\n");  /* put a separator */
    }
}

转载于:https://my.oschina.net/yumm007/blog/1797989

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值