(原)lua使用ffi调用c程序的函数
2016-08-27 12:09
423 查看
转载请注明出处:
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,输入:
说明:包含三个函数:isquare计算平方,isqrt计算开方,ivecadd计算两个数组对应元素之和。
2. 在终端中输入:
此时当前文件夹内会生成libcalcmath.so。
说明:不能使用gcc,会提示如下错误:
截图如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827121026819-1774336183.png)
3. 新建调用该库的lua文件:calcmath.lua(名字随便),并输入:
说明:a上面注释的代码实际可以直接使用,此时在当前文件内直接调用c函数。如果只在当前文件使用calcmath,可以加上local,如local calcmath = {}。如果要在其他文件内使用calcmath,则不能加上local,否则会提示:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120008569-2082848576.png)
b 该文件名字如果为ffi.lua的话,可能不能在其他文件内成功调用(应该是与系统文件ffi.lua冲突):
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120546351-228038114.png)
也可能能调用成功(在另一台电脑上试了一下,如果用include则失败,如果用dofile则成功。。。)。
160830更新:刚才又试了一下,即便该文件名字为‘ffi.lua’,无论是include还是dofile,都能成功:test.lua的前6行如下:
如果不加第一句require就不行。估计程序能区分开哪个是系统的库文件,哪个是当前的文件。。。先将就着这样理解吧。
c libcalcmath.so文件可以放在当前文件夹下,也可以放在/usr/lib下;不论放在当前文件夹还是/usr/lib下,代码中均不用加上lib及.so,ffi.load 时会自动添加。当然在代码中也可以加上,如libcalcmath或libcalcmath.so或calcmath.so。我这边试了,如果放在其他文件夹下,需要使用绝对路径,并且需要使用库的完整名libcalcmath.so,如:/home/XXX/libcalcmath.so,否则会提示:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120559897-1594257379.png)
4. 新建测试程序test.lua,并输入:
说明:a第一句local ffi = require("ffi")必须要,否则下面的ffi.new无法使用。
b 不确定是否需要释放new出来的内存。。。(以后碰到了再说吧)。
5. 结果:
使用th test.lua结果如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120725413-1638803424.png)
无法使用lua test.lua,会提示如下的错误:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120737054-1210208543.png)
使用luajit test.lua,结果如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120750491-1016643247.png)
说明:
如果isqrt中参数类型使用float的话,精度会有损失,结果为:
2.2360680103302
使用double后,结果为:
2.2360679774998
使用计算器的结果:
2.2360679774997896964091736687313
可见,使用double后,精度范围内结果一致。
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,输入:
#include <iostream> #include <cmath> #include <stdio.h> //using namespace std; extern "C" { float isquare(float val); double isqrt(double val); void ivecadd(double* a, double* b, int len); } float isquare(float val) { return val*val; } double isqrt(double val) { return sqrt(val); } void ivecadd(double* a, double* b, int len) { for (int i = 0; i < len; ++i) { a[i] = a[i] + b[i]; } }
说明:包含三个函数:isquare计算平方,isqrt计算开方,ivecadd计算两个数组对应元素之和。
2. 在终端中输入:
g++ -shared -fPIC -o libcalcmath.so calcmath.cpp
此时当前文件夹内会生成libcalcmath.so。
说明:不能使用gcc,会提示如下错误:
undefined symbol: _ZNSt8ios_base4InitD1Ev
截图如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827121026819-1774336183.png)
3. 新建调用该库的lua文件:calcmath.lua(名字随便),并输入:
calcmath = {} local ffi = require("ffi") ffi.cdef[[ float isquare(float val); double isqrt(double val); void ivecadd(double* a, double* b, int len); ]] calcmath.C = ffi.load('calcmath') --[[local squareVal = calcmath.C.isquare(5) -- call functions in this file print(squareVal) local sqrtVal = calcmath.C.isqrt(5) print(sqrtVal) local a = ffi.new('double[2]', {5.2, 6.7}) local b = ffi.new("double[2]", {3, 7}) local x = ffi.cast('double&',a) local y = ffi.cast('double&',a+1) calcmath.C.ivecadd(a, b, ffi.sizeof(a)/8) print(tonumber(x), tonumber(y)) print(ffi.sizeof(a)) ]]
说明:a上面注释的代码实际可以直接使用,此时在当前文件内直接调用c函数。如果只在当前文件使用calcmath,可以加上local,如local calcmath = {}。如果要在其他文件内使用calcmath,则不能加上local,否则会提示:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120008569-2082848576.png)
b 该文件名字如果为ffi.lua的话,可能不能在其他文件内成功调用(应该是与系统文件ffi.lua冲突):
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120546351-228038114.png)
也可能能调用成功(在另一台电脑上试了一下,如果用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,否则会提示:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120559897-1594257379.png)
4. 新建测试程序test.lua,并输入:
local ffi = require("ffi") --include 'calcmath.lua' -- this line and the following 2 line are both ok require 'paths' paths.dofile('calcmath.lua') local C = calcmath.C local squareVal = C.isquare(5) print(squareVal) local sqrtVal = C.isqrt(5) print(sqrtVal) local a = ffi.new('double[2]', {5.2, 6.7}) local b = ffi.new("double[2]", {3, 7}) local x = ffi.cast('double&',a) local y = ffi.cast('double&',a+1) C.ivecadd(a, b, ffi.sizeof(a)/8) print(tonumber(x), tonumber(y)) print(ffi.sizeof(a))
说明:a第一句local ffi = require("ffi")必须要,否则下面的ffi.new无法使用。
b 不确定是否需要释放new出来的内存。。。(以后碰到了再说吧)。
5. 结果:
使用th test.lua结果如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120725413-1638803424.png)
无法使用lua test.lua,会提示如下的错误:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120737054-1210208543.png)
使用luajit test.lua,结果如下:
![](https://images2015.cnblogs.com/blog/682463/201608/682463-20160827120750491-1016643247.png)
说明:
如果isqrt中参数类型使用float的话,精度会有损失,结果为:
2.2360680103302
使用double后,结果为:
2.2360679774998
使用计算器的结果:
2.2360679774997896964091736687313
可见,使用double后,精度范围内结果一致。
相关文章推荐
- 使用CreateProcess函数实现隐秘的程序调用
- 使用 lua 调用 c 语言写的函数
- 在C程序中使用系统调用函数 rename()
- (转)程序性能调优之 怎样使用gprof和oprofile来分析 linux程序的性能(每个函数的调用次数与耗时)
- Lua 在C程序中调用Lua函数
- 使用CreateProcess函数实现隐秘的程序调用之二:使用匿名管道
- Lua的使用入门之在C++程序中调用lua函数1
- C 函数中调用Lua函数时,对于lua_pcall使用的困惑
- 程序性能调优之 怎样使用gprof和oprofile来分析 linux程序的性能(每个函数的调用次数与耗时)
- 使用CreateProcess函数实现隐秘的程序调用之二:使用匿名管道
- 程序性能调优之 怎样使用gprof和oprofile来分析 linux程序的性能(每个函数的调用次数与耗时)
- 函数指针使用与直接函数调用对程序代码大小的影响
- CLisp 13:使用包FFI在CLisp中调用C语言写的函数
- Linux:使用rpcgen实现64位程序调用32位库函数
- cocos2dx中注册导出c++函数供lua调用(使用tolua++)
- C 函数中调用Lua函数时,对于lua_pcall使用的困惑
- tolua 使用 Lua调用c++多返回值函数
- 使用C#调用存储过程,用函数合理组织代码,使程序更加的清晰(示例)
- 在JAVA中使用LUA脚本记,javaj调用lua脚本的函数(转)
- 使用gprof 或 valgrind查看函数调用频率及程序性能瓶颈调试