在Lua中调用C函数

Lua调用C语言中的函数是通过栈来进行参数传递的,这与大部分编程语言的内部函数调用的实现一致。

我们先实现如下C代码

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
#include <lualib.h>  
#include <lauxlib.h>  
  
#include <stdio.h>  
#include <sys/time.h>  
  
static int (lua_State * L)  
{  
      
    double a = luaL_checknumber(L, 1);  
    printf("第一个参数:%fn", a);  
  
    // 获取第二个函数参数  
    double b = luaL_checknumber(L, 2);  
    printf("第二个参数:%fn", b);  
  
    // 设置函数返回值  
    lua_pushnumber(L, a + b);  
  
    // 函数返回值的数量,在这里函数返回值为1  
    return 1;  
}  
  
static int i_swap(lua_State * L)  
{  
    int i = lua_tointeger(L, 1);  
    int j = lua_tointeger(L, 2);  
    printf("%d 和 %d 交换位置n", i, j);  
  
    lua_pushinteger(L, j);  
    lua_pushinteger(L, i);  
  
    return 2;  
}  
  
// 计算斐波拉契数列  
static int i_fib(lua_State * L)  
{  
    // lua_Integer长度为64位,防止溢出(事实上当n的值达到100左右即使64位也会发生溢出了)  
    lua_Integer sum = 0;  
    lua_Integer a = 0; // n - 2  
    lua_Integer b = 0; // n - 1  
  
    int n = lua_tointeger(L, 1);  
    int i = 0;  
    while (i <= n) {  
        // printf("sum is %dn", sum);  
        i++;  
        if (i == 1) {  
            a = 0;  
            b = 1;  
        }  
        sum = a + b;  
        a = b;  
        b = sum;  
    }  
  
    lua_pushinteger(L, sum);  
    return 1;  
}  
  
// 获取当前的毫秒时间戳  
static int i_time(lua_State * L)  
{  
    struct timeval tv;  
    gettimeofday( &tv, NULL );  
    double t = tv.tv_sec + (double)((int)(tv.tv_usec*0.001) * 0.001);  
  
    // 以整数返回  
    lua_pushinteger(L, (lua_Integer)(t * 1000));  
    return 1;  
}  
  
// 打开名为mylib的库,在Lua中使用require('mylib')可以调用mylib中的函数  
int luaopen_mylib(lua_State * L)  
{  
    // 对函数进行注册,之后在Lua中可以直接调用  
    lua_register(L, "add", i_add);  
    lua_register(L, "swap", i_swap);  
    lua_register(L, "fib_c", i_fib);  
    lua_register(L, "current_time", i_time);  
    return 0;  
}  

—|—

我们把上面的代码保存在 mylib.c 文件中,随后使用如下命令对源代码进行编译得到 mylib.so 文件

gcc mylib.c -fPIC -shared -o mylib.so -I/usr/local/include/lua5.3 -llua5.3

得到动态链接库之后我们在当前文件夹下创建 test.lua 文件,之后输入如下代码

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
package.cpath = './?.so;' .. package.cpath -- 把库文件添加到环境变量中  
  
require('mylib')  
print(add(1, 2))  
print(swap(2333, 666))  
  
-- 计算斐波那契数列  
fib_lua = function(n)  
    sum = 0  
    a = 0 -- n - 2  
    b = 0 -- n - 1  
  
    i = 0  
    repeat  
        i = i + 1  
        if i == 1 then  
            a = 0  
            b = 1  
        end  
        sum = a + b  
        a = b  
        b = sum  
    until i > n  
    return sum  
end  
  
n = 10000000 -- 计算的斐波那契数列位数  
  
-- 使用lua计算  
start = current_time()  
fib_lua(n)  
luaCost = current_time() - start  
print(luaCost)  
  
-- 使用C语言计算  
start = current_time()  
fib_c(n)  
cCost = current_time() - start  
print(cCost)  
  
-- 计算lua与C语言的耗时比  
print(luaCost / cCost)  

—|—

执行 lua test.lua 得到如下结果:

第一个参数:1.000000
第二个参数:2.000000
3.0
2333 和 666 交换位置
666     2333
1887
40
47.175

至此我们就使用Lua成功的调用了C语言中的函数,我们发现C语言的执行效率差不多是Lua的四十多倍(C语言的执行效率是Python的80多倍),可见Lua作为一个脚本语言,其执行速度还是很快的。

参考

Lua 5.3 参考手册

糖果

糖果
LUA教程

Lapis框架的常用处理方法

Lapis框架的常用处理方法 Continue reading

MoonScript实现选择排序

Published on February 26, 2017

MoonScript与Redis客户端

Published on January 19, 2017