Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Ruby-FFI:多维数组_C_Ruby_Arrays_Ffi - Fatal编程技术网

C Ruby-FFI:多维数组

C Ruby-FFI:多维数组,c,ruby,arrays,ffi,C,Ruby,Arrays,Ffi,我试图从Ruby调用的C函数如下: void foo(double *in_array, double *out_array) module FooLib extend FFI::Library ffi_lib "foo.so" attach_function :Foo, [:pointer, :pointer], :void end 其中: in_array是“foo”将用于 计算并返回: out\u array也是一个数组数组,C函数将更改其内容 我的包装看起来像这样:

我试图从Ruby调用的C函数如下:

void foo(double *in_array, double *out_array)
module FooLib
  extend FFI::Library
  ffi_lib "foo.so"
  attach_function :Foo, [:pointer, :pointer], :void
end
其中:

  • in_array
    是“foo”将用于 计算并返回:
  • out\u array
    也是一个数组数组,C函数将更改其内容
我的包装看起来像这样:

void foo(double *in_array, double *out_array)
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中创建这些结构?

直接从该文件:

在某些情况下,需要分配本机内存并将该缓冲区交给外部库。然后外部库处理该缓冲区的生命周期,包括最终释放它

包装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
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
在ruby代码中,对这些函数的调用将返回FFI::指针。使用FFI::Pointer上定义的方法将数据从ruby内存移动到本机内存

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
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

按照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

当您需要FFI的指针时,只需声明一个

# some_pointer = FFI::MemoryPointer.new(:type, size)
some_pointer = FFI::MemoryPointer.new(:double, 8)
这将适用于单变量。不过,我们都需要查阅FFI文档以了解阵列。 数组指针一定有什么东西。
我的问题与此类似

谢谢你。我已经看到了这一点(在我的问题末尾,我提到了LibC包装器)。但是一旦你有了它,如何将它应用到多维数组就不再简单了。我将添加一个答案,解释如何做到这一点。是的,绝对。我本想更新我的答案,但你确实可以在数组中执行
\u ptr=FFI::MemoryPointer.new(FFI.type\u size(FFI::type\u FLOAT64)*在数组中执行
。我就是这样做的,很好。很高兴你找到了答案。谢谢大家的投票。