• (原)lua使用ffi调用c程序的函数


    转载请注明出处:

    http://www.cnblogs.com/darkknightzh/p/5812763.html

    参考网址:

    http://luajit.freelists.narkive.com/Yhm9jicx/unexpected-type-conversion-for-arithmetic-with-cdata-double

    http://luajit.org/ext_ffi_semantics.html#convert_fromlua

    https://github.com/szagoruyko/loadcaffe

    1. 新建calcmath.cpp,输入:

     1 #include <iostream>
     2 #include <cmath>
     3 #include <stdio.h>
     4 //using namespace std;
     5 
     6 
     7 extern "C" {
     8 float isquare(float val);
     9 double isqrt(double val);
    10 void ivecadd(double* a, double* b, int len);
    11 }
    12 
    13 float isquare(float val)
    14 {
    15     return val*val;
    16 }
    17 
    18 double isqrt(double val)
    19 {
    20     return sqrt(val);
    21 }
    22 
    23 void ivecadd(double* a, double* b, int len)
    24 {
    25     for (int i = 0; i < len; ++i)
    26     {
    27         a[i] = a[i] + b[i];
    28     }
    29 }

    说明:包含三个函数:isquare计算平方,isqrt计算开方,ivecadd计算两个数组对应元素之和。

    2. 在终端中输入:

    g++ -shared -fPIC -o libcalcmath.so calcmath.cpp

    此时当前文件夹内会生成libcalcmath.so。

    说明:不能使用gcc,会提示如下错误:

    undefined symbol: _ZNSt8ios_base4InitD1Ev

    截图如下:

    3. 新建调用该库的lua文件:calcmath.lua(名字随便),并输入:

     1 calcmath = {}
     2 
     3 local ffi = require("ffi")
     4 
     5 ffi.cdef[[
     6 float isquare(float val);
     7 double isqrt(double val);
     8 void ivecadd(double* a, double* b, int len);
     9 ]]
    10 
    11 calcmath.C = ffi.load('calcmath')
    12 
    13 --[[local squareVal = calcmath.C.isquare(5)    -- call functions in this file
    14 print(squareVal)
    15 local sqrtVal = calcmath.C.isqrt(5)
    16 print(sqrtVal)
    17 
    18 local a = ffi.new('double[2]', {5.2, 6.7})
    19 local b = ffi.new("double[2]", {3, 7})
    20 
    21 local x = ffi.cast('double&',a)
    22 local y = ffi.cast('double&',a+1)
    23 
    24 calcmath.C.ivecadd(a, b, ffi.sizeof(a)/8)
    25 print(tonumber(x), tonumber(y))
    26 print(ffi.sizeof(a))
    27 ]]

    说明:a上面注释的代码实际可以直接使用,此时在当前文件内直接调用c函数。如果只在当前文件使用calcmath,可以加上local,如local calcmath = {}。如果要在其他文件内使用calcmath,则不能加上local,否则会提示:

    b 该文件名字如果为ffi.lua的话,可能不能在其他文件内成功调用(应该是与系统文件ffi.lua冲突):

    也可能能调用成功(在另一台电脑上试了一下,如果用include则失败,如果用dofile则成功。。。)。

    160830更新:刚才又试了一下,即便该文件名字为‘ffi.lua’,无论是include还是dofile,都能成功:test.lua的前6行如下:

    local ffi = require("ffi")
    
    --include 'ffi.lua'       -- this line and the following 2 line are both ok
    
    require 'paths'
    paths.dofile('ffi.lua')

    如果不加第一句require就不行。估计程序能区分开哪个是系统的库文件,哪个是当前的文件。。。先将就着这样理解吧。

    c libcalcmath.so文件可以放在当前文件夹下,也可以放在/usr/lib下;不论放在当前文件夹还是/usr/lib下,代码中均不用加上lib及.so,ffi.load 时会自动添加。当然在代码中也可以加上,如libcalcmath或libcalcmath.so或calcmath.so。我这边试了,如果放在其他文件夹下,需要使用绝对路径,并且需要使用库的完整名libcalcmath.so,如:/home/XXX/libcalcmath.so,否则会提示:

    4. 新建测试程序test.lua,并输入:

     1 local ffi = require("ffi")
     2 
     3 --include 'calcmath.lua'       -- this line and the following 2 line are both ok
     4 
     5 require 'paths'
     6 paths.dofile('calcmath.lua')
     7 
     8 local C = calcmath.C
     9 
    10 local squareVal = C.isquare(5)
    11 print(squareVal)
    12 local sqrtVal = C.isqrt(5)
    13 print(sqrtVal)
    14 
    15 local a = ffi.new('double[2]', {5.2, 6.7})
    16 local b = ffi.new("double[2]", {3, 7})
    17 
    18 local x = ffi.cast('double&',a)
    19 local y = ffi.cast('double&',a+1)
    20 
    21 C.ivecadd(a, b, ffi.sizeof(a)/8)
    22 print(tonumber(x), tonumber(y))
    23 print(ffi.sizeof(a))

    说明:a第一句local ffi = require("ffi")必须要,否则下面的ffi.new无法使用。

    b 不确定是否需要释放new出来的内存。。。(以后碰到了再说吧)。

    5. 结果:

    使用th test.lua结果如下:

    无法使用lua test.lua,会提示如下的错误:

    使用luajit test.lua,结果如下:

    说明

    如果isqrt中参数类型使用float的话,精度会有损失,结果为:

    2.2360680103302

    使用double后,结果为:

    2.2360679774998

    使用计算器的结果:

    2.2360679774997896964091736687313

    可见,使用double后,精度范围内结果一致。

  • 相关阅读:
    百度AI开放平台 情感倾向分析实例以及gbk编码解决
    根据cid获取哔哩哔哩弹幕
    python3 doc2vec文本聚类实现
    python3 LDA主题模型以及TFIDF实现
    偶得李春芬先生书信一函
    STATA一小步 我的一大步
    2013-2015南京大学历史学系若干考试题目汇编
    ArcPy批量计算Mean Center的两个实例
    解决Gephi导入csv文件时提示“边表格需要一个包含节点标号‘源’和‘目标’列” 问题的两个方案
    Vertx 实现webapi实战项目(二)
  • 原文地址:https://www.cnblogs.com/darkknightzh/p/5812763.html
Copyright © 2020-2023  润新知