`
fantaxy025025
  • 浏览: 1328366 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

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

    博客分类:
  • lua
 
阅读更多

=

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

=

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

看一下是不是成功了

编译Lua

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

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一下看看行不行。

果然报错了!

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

-l参数和-L参数
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文
件名有什么关系呢?
就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的
头lib和尾.so去掉就是库名了

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

执行成功!

如何让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编译执行

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

为什么呢?查了一些资料发现因为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

参考资料:
https://www.cnblogs.com/pied/archive/2012/10/26/2741601.html
http://blog.csdn.net/vermilliontear/article/details/50947379
http://blog.csdn.net/casularm/article/details/316149

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

 

=

=

=

 

分享到:
评论

相关推荐

    lua和c语言之间相互调用实例

    在IT领域,编程语言间的互操作性是至关重要的,尤其是当需要将低级语言(如C)的强大性能与高级语言...在提供的压缩文件`cluatest.rar`和`luac.rar`中,可能包含了具体的示例代码和实践教程,供你进一步学习和研究。

    所有版本LUA源码

    所有版本LUA源码 lua-5.3.5 lua-5.3.4 lua-5.3.3 lua-5.3.2 lua-5.3.1 lua-5.3.0 lua-5.2.4 lua-5.2.3 lua-5.2.2 lua-5.2.1 lua-5.2.0 lua-5.1.5 lua-5.1.4 lua-5.1.3 lua-5.1.2 lua-5.1.1 lua-5.1 lua-5.0.3 lua-...

    lua-nginx-module-0.10.13

    Lua-Nginx-Module,简称lua-nginx-module,是Nginx服务器的一个重要扩展模块,它将强大的Lua脚本语言集成到Nginx中,允许用户在Nginx配置文件中直接编写Lua代码,极大地增强了Nginx的功能性和灵活性。版本0.10.13是...

    C语言调用Lua代码

    在Linux底下,从C语言调用Lua代码的一个简单例子。

    lua-nginx-module-0.10.9rc7

    例如,使用`lua_code_cache on|off`来控制Lua代码缓存策略,用`set_by_lua_file`或`access_by_lua_file`等指令执行Lua脚本。 4. **测试与启动**:在修改配置后,务必先运行`nginx -t`测试配置文件的正确性,无误后...

    lua-nginx-module-master.zip

    2. **配置使用**:在Nginx的配置文件(如`nginx.conf`)中,你可以通过`lua_code_cache`指令控制Lua脚本的缓存策略,`init_by_lua_file`或`init_by_lua`用于执行启动时的Lua代码,`set_by_lua_block`、`rewrite_by_...

    luajava-1.1-x64-lua51

    Luajava的核心是它的绑定机制,通过Java Native Interface (JNI) 实现,使得Lua与Java之间可以进行低级别的数据交换和调用。 在"luajava-1.1-x64-lua51"这个包中,"lua51"指的是Lua 5.1版本,这是Lua的一个稳定版本...

    lua-devel-5.3.4-12.el8.aarch64

    此外,`lua_gettop`、`lua_pushnumber` 和 `lua_pcall` 等函数提供了在 C 代码中与 Lua 脚本进行数据交换和调用 Lua 函数的能力。 在 aarch64 平台上,开发者需要注意一些特定的架构问题,比如内存对齐、指令集的...

    32位,64位的 luajava-1.1-x64-lua51.zip

    luajava-1.1.jar 文件是 Java 类库,包含了 luajava 的所有 Java 代码,这些代码提供了与 Lua 的接口,使得 Java 代码可以加载和执行 Lua 脚本,同时 Lua 也可以调用 Java 类的方法。而 luajava-1.1.dll 文件则是 ...

    delphi7与lua相互调用的例子

    总结来说,"delphi7与lua相互调用的例子"是一个关于如何在Delphi 7应用程序中嵌入和调用Lua脚本的实例。它展示了如何利用DLL接口将这两种语言的强项结合在一起,为开发带来更多的可能性。通过深入理解这个示例,...

    OC与Lua交互调用(不使用第三方库)Demo

    在Lua中调用Objective-C的方法,首先需要在OC代码中暴露接口。这通常通过实现`luaopen`函数来完成,该函数会在Lua环境中注册C函数。例如,我们可以创建一个名为`registerObjCLuaFunctions`的函数,将OC类的方法绑定...

    VC和lua相互调用的例子

    总结起来,实现VC和lua的相互调用,关键在于理解lua的API,正确地初始化和管理lua状态机,以及有效地在两者之间传递数据和调用函数。这种交互方式极大地增强了VC程序的灵活性和可扩展性,尤其适合那些需要动态配置或...

    lua-cjson-2.1.0

    `lua-cjson`是Lua编程语言中一个高效且功能丰富的JSON(JavaScript Object Notation)解析和序列化库,版本2.1.0提供了稳定性和性能上的优化。这个库使得在Lua环境中处理JSON数据变得异常简单,尤其在Web开发中,如...

    lua与C相互调用例子程序

    这个例子程序可能包含了一个简单的Lua脚本和一个C源文件,展示了如何在Lua中调用C函数,以及在C代码中调用Lua函数的过程。测试文件“test”可能是 Lua 脚本或者编译后的库文件,具体要看实际内容。 学习和理解这种...

    lua-cjson-2.1.0-已编译

    2. `lua_cjson.luac` 或 `lua_cjson.lua`:这是Lua源代码或预编译的脚本,定义了如何在Lua环境中使用cjson模块。 3. `README`:包含库的使用说明、安装指南和许可信息。 4. `LICENSE`:库的授权协议,规定了用户可以...

    Lua for Windows 5.1.4-45

    Lua for Windows 5.1.4-45 Lua for Windows 5.1.4-45 Lua for Windows 5.1.4-45

    nginx、lua、jwt安装包及蓝绿发布代码

    lua-nginx-module-0.10.22.tar.gz # 0.10.16 以后都需要 lua-resty-core和lua-resty-lrucache lua-resty-core-0.1.24.tar.gz [lua-nginx-module依赖] lua-resty-lrucache-0.12.tar ngx_devel_kit-0.3.2.tar.gz nginx...

    cocos2D-lua 核心编程内置代码

    1. 场景(Scene):在Cocos2d-lua中,每个游戏状态或屏幕对应一个场景,场景之间可以互相切换。 2. 层(Layer):场景由多个层组成,层是显示内容的基本单元,可以包含精灵、文本、菜单等元素。 3. 精灵(Sprite):...

    lua-resty-limit-traffic, 在 openresty/ngx_lua中,用于限制和控制流量的Lua库.zip

    lua-resty-limit-traffic, 在 openresty/ngx_lua中,用于限制和控制流量的Lua库 电子邮件名称lua-resty-limit-traffic - 用于限制和控制 openresty/ngx_lua中流量的Lua库目录名称状态概要说明描述安装工具社区服务...

    lua-resty-redis-connector-master

    《lua-resty-redis-connector:Lua在OpenResty中的Redis连接器详解》 在现代Web服务开发中,Lua作为一种轻量级脚本语言,因其高效、简洁的特性被广泛应用于服务器端。OpenResty是基于Nginx的高性能Web平台,它集成...

Global site tag (gtag.js) - Google Analytics