我试图从Ruby调用的C函数是这样的:
void foo(double *in_array, double *out_array)
其中:
in_array
是“foo”将使用的数组数组
计算并返回:out_array
也是一个数组数组,C函数将改变其内容。我的包装器看起来像这样:
module FooLib
extend FFI::Library
ffi_lib "foo.so"
attach_function :Foo, [:pointer, :pointer], :void
end
我在Ruby中做了以下事情:
# Allocate the objects and prepare them
in_array = Matrix.build(10, 3) { rand }.to_a
out_array = Matrix.build(10, 3) { 0 }.to_a
FooLib.Foo(in_array, out_array)
但是我收到以下错误:
:pointer argument is not a valid pointer (ArgumentError)
我可以理解我需要使用指向这些数组的指针而不是数组对象,但我不知道如何做到这一点。这是否意味着我需要使用LibC包装器在C中创建这些结构?
答案 0 :(得分:2)
Per Momer的回答,看起来你确实需要使用LibC包装器。将多维数组转换为正确的指针并不简单,所以我想我会把它放在这里,以防它帮助其他人:
in_array = Matrix.build(10, 3) { rand }.to_a
in_array_flattened = in_array.transpose.flatten # Just flatten your multi-dim array
in_array_ptr = LibC.malloc(FFI.type_size(FFI::TYPE_FLOAT64) * in_array_flattened.size) # Watchout the type you want to use.
in_array_ptr.write_array_of_double(in_array.flatten)
# Same for out_array
FooLib.Foo(in_array_ptr, out_array_ptr)
# Convert back to Ruby
values = in_array_ptr.read_array_of_double(in_array_flattened.length)
values = values.enum_for(:each_slice, 10).to_a.transpose # Might be the C lib I am using but you do need to do this conversion in my case to get the multi-dim array you are expecting
答案 1 :(得分:1)
当您需要FFI指针时,只需声明一个。
# some_pointer = FFI::MemoryPointer.new(:type, size)
some_pointer = FFI::MemoryPointer.new(:double, 8)
这适用于单个变量。我们都需要查询阵列的FFI文档。 http://rubydoc.info/github/ffi/ffi/FFI 关于数组指针必须有一些东西。 我的问题类似于I am familiar with Ruby /DL but not sure how to use the C function calls that have pointers for return parameters
答案 2 :(得分:0)
FFI documentation about pointers.
详细解释了发生在您身上的事情直接来自该文件:
某些情况需要分配本机内存并将该缓冲区移交给外部库。然后外部库处理该缓冲区的生命周期,包括最终释放它。
包装libc并使用其malloc和free函数来分配和释放本机内存。
module LibC
extend FFI::Library
ffi_lib FFI::Library::LIBC
# memory allocators
attach_function :malloc, [:size_t], :pointer
attach_function :calloc, [:size_t], :pointer
attach_function :valloc, [:size_t], :pointer
attach_function :realloc, [:pointer, :size_t], :pointer
attach_function :free, [:pointer], :void
# memory movers
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
attach_function :bcopy, [:pointer, :pointer, :size_t], :void
end # module LibC
在ruby代码中,对这些函数的调用将返回FFI :: Pointers。使用FFI :: Pointer上定义的方法将数据从ruby内存移动到本机内存。
foo = "a ruby string"
bar = 3.14159
baz = [1, 2, 3, 4, 5]
buffer1 = LibC.malloc foo.size
buffer1.write_string foo
buffer2 = LibC.malloc bar.size
buffer2.write_float bar
# all of the array elements need to be the same type
# meaning you can't mix ints, floats, strings, etc.
buffer3 = LibC.malloc(baz.first.size * baz.size)
buffer3.write_array_of_int baz