C和Lua之间的相互调用-代码例子2

栏目: Lua · 发布时间: 6年前

内容简介:=这个例子,写的更详细一些。=

=

这个例子,写的更详细一些。

=

C和 Lua 之间的相互调用  https://www.cnblogs.com/lijiajia/p/8284328.html

前面的话

第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的。这次打算好好了解一下C跟lua是如何交互的

那么如何使用Lua语言?

lua是 c语言 编写的,而且开源。可以在https://www.lua.org官网上下载Lua的源码,然后尝试编译它!是不是跟我一样好激动,一直用集成环境,写上层语言,今天居然要碰编译了!!~ 可怎么编译呢?

让我们召唤出编译神器: gcc! 【GNU编译器套件(GNU Compiler Collection)包括C、C++、Objective-C、Fortran、 Java 、Ada和 Go 语言的前端,也包括了这些语言的库(如libstdc++、libgcj等等)。】

在Mac上安装GCC

如果你安装了Homebrew的话,只要一行就可以了。

brew install gcc

装完后用

brew info gcc
或者
gcc -v

看一下是不是成功了

C和Lua之间的相互调用-代码例子2

编译Lua

当你安装好了编译器后,编译lua就变得非常简单了

C和Lua之间的相互调用-代码例子2

Lua官网的文档里有说编译方式, 但MakeFile里默认的是编译成静态链接库,被这个坑了,后面再说

建议安装在/opt目录下

sudo su
cd /opt
curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz
tar zxf lua-5.3.4.tar.gz
cd lua-5.3.4
make macosx test
make macosx install

安装好后用lua -v查看下如果有信息, 恭喜你,Lua编译好了!~

下面正式开干了~

写一个C调用Lua的Demo编译运行

add.c内容

//你需要include这几个lua头文件
#include        <stdio.h>
#include        "lua.h"
#include        "lualib.h"
#include        "lauxlib.h"

lua_State* L;
int
luaadd(int x, int y)
{
    int sum;
    /*函数名*/
    lua_getglobal(L,"add");
    /*参数入栈*/
    lua_pushnumber(L, x);
    /*参数入栈*/
    lua_pushnumber(L, y);
    /*开始调用函数,有2个参数,1个返回值*/
    lua_call(L, 2, 1);
    /*取出返回值*/
    sum = (int)lua_tonumber(L, -1);
    /*清除返回值的栈*/
    lua_pop(L,1);
    return sum;
}

int
main(int argc, char *argv[])
{
    int sum;
    L = luaL_newstate();  /* 创建lua状态机 */
    luaL_openlibs(L);   /* 打开Lua状态机中所有Lua标准库 */
    /*加载lua脚本*/
    luaL_dofile(L, "add.lua");
    /*调用C函数,这个里面会调用lua函数*/
    sum = luaadd(99, 10);
    printf("The sum is %d \n",sum);
    /*清除Lua*/
    lua_close(L);
    return 0;
}

add.lua放到与C同级的目录下,里面写一个简单的函数,让C调用

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

好了,终于到了用GCC编译的阶段了,直接gcc add.c一下看看行不行。

C和Lua之间的相互调用-代码例子2

果然报错了!

这是因为没有把add.c里面的函数链接到我们前面编译出来的lua库里导致的。怎么让他指定链接哪个库呢?看GCC的文档得知-l参数可以指定要链接的库

-l参数和-L参数

-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文

件名有什么关系呢?

就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的

头lib和尾.so去掉就是库名了

那我们再试一下,gcc add.c -llua,这次编译出来了: a.out

C和Lua之间的相互调用-代码例子2

执行成功!

如何让Lua调用C?

Lua调用C,我了解到的有3种方式

1.通过在C中注册函数给lua调用

2.封装成c动态链接库,在lua中require

3.在LuaJIT里面可以使用ffi高性能的调用C(但是IOS上不支持LuaJIT。。)

1.在C中注册函数给Lua

lua提供了lua_register函数注册C函数给lua端调用

hello.c

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


static int l_SayHello(lua_State *L)
{
    const char *d = luaL_checkstring(L, 1);//获取参数,字符串类型
    int len = strlen(d);
    char str[100] = "hello ";
    strcat(str, d);
    lua_pushstring(L, str);  /* 返回给lua的值压栈 */
    return 1;
}

int
main(int argc, char *argv[])
{
    lua_State *L = luaL_newstate();  /* 创建lua状态机 */
    luaL_openlibs(L);   /* 打开Lua状态机中所有Lua标准库 */
    lua_register(L, "SayHello", l_SayHello);//注册C函数到lua

    const char* testfunc = "print(SayHello('lijia'))";//lua中调用c函数
    if(luaL_dostring(L, testfunc))    // 执行Lua命令。
        printf("Failed to invoke.\n");

    /*清除Lua*/
    lua_close(L);
    return 0;
}

gcc -o hello hello.c -llua编译执行

C和Lua之间的相互调用-代码例子2

2.调用C动态链接库

创建一个mylib.c的文件,然后我们把它编译成动态链接库

#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

/* 所有注册给Lua的C函数具有
 * "typedef int (*lua_CFunction) (lua_State *L);"的原型。
 */
static int l_sin(lua_State *L)
{   
    // 如果给定虚拟栈中索引处的元素可以转换为数字,则返回转换后的数字,否则报错。
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));  /* push result */

    /* 这里可以看出,C可以返回给Lua多个结果,
     * 通过多次调用lua_push*(),之后return返回结果的数量。
     */
    return 1;  /* number of results */
}

/* 需要一个"luaL_Reg"类型的结构体,其中每一个元素对应一个提供给Lua的函数。
 * 每一个元素中包含此函数在Lua中的名字,以及该函数在C库中的函数指针。
 * 最后一个元素为“哨兵元素”(两个"NULL"),用于告诉Lua没有其他的函数需要注册。
 */
static const struct luaL_Reg mylib[] = {
    {"mysin", l_sin},
    {NULL, NULL}
};

/* 此函数为C库中的“特殊函数”。
 * 通过调用它注册所有C库中的函数,并将它们存储在适当的位置。
 * 此函数的命名规则应遵循:
 * 1、使用"luaopen_"作为前缀。
 * 2、前缀之后的名字将作为"require"的参数。
 */
extern int luaopen_mylib(lua_State* L)
{
    /* void luaL_newlib (lua_State *L, const luaL_Reg l[]);
     * 创建一个新的"table",并将"l"中所列出的函数注册为"table"的域。
     */ 
    luaL_newlib(L, mylib);

    return 1;
}

使用gcc -o mylib.so -fPIC -shared mylib.c -llua -ldl编译成so

然后创建一个lua文件,把我们编译出来的c库引入进来

--[[ 这里"require"的参数对应C库中"luaopen_mylib()"中的"mylib"。
     C库就放在"a.lua"的同级目录,"require"可以找到。]]
local mylib = require "mylib"

-- 结果与上面的例子中相同,但是这里是通过调用C库中的函数实现。
print(mylib.mysin(3.14 / 2))    --> 0.99999968293183

执行a.lua文件,后报错,说Lua存在多个虚拟机!

lua: multiple Lua VMs detected

C和Lua之间的相互调用-代码例子2

为什么呢?查了一些资料发现因为lua默认编译的是静态链接库,这样会导致链接多个VM冲突。

那么我们自己再编译个lua解释器动态链接一下。

mylua.c

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

int main() {

    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
if (luaL_loadfile(L, "a.lua") || lua_pcall(L, 0, 0, 0)) {
        printf("%s", lua_tostring(L, -1));
    }

}

gcc -o mylua mylua.c -llua -ldl -lm -Wall

这样就能编译出mylua可执行文件

在命令行./mylua执行,成功打印出0.99999968293183

总结

gcc命令,编译lua,编译C动态链接库这些之前都接触的比较少。所以也爬了不少坑,哈哈哈。接下来要好好研究下怎么在c中解析二进制协议给lua调用,在c中怎么封装好luatable

转载请注明出处: 那个少年-  http://www.cnblogs.com/lijiajia

=

=

=


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Scalability for Startup Engineers

Web Scalability for Startup Engineers

Artur Ejsmont / McGraw / 2015-6-23 / USD 34.81

Design and build scalable web applications quickly This is an invaluable roadmap for meeting the rapid demand to deliver scalable applications in a startup environment. With a focus on core concept......一起来看看 《Web Scalability for Startup Engineers》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具