轉載請註明出處:html
http://www.cnblogs.com/darkknightzh/p/5812763.htmlios
參考網址:git
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計算兩個數組對應元素之和。ui
2. 在終端中輸入:this
g++ -shared -fPIC -o libcalcmath.so calcmath.cpp
此時當前文件夾內會生成libcalcmath.so。lua
說明:不能使用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後,精度範圍內結果一致。