我正在努力让我了解红宝石FFI。没有办法利用FFI回调的返回值吗?
这是我的最小示例:
require 'ffi'
class Foo
extend FFI::Library
ffi_lib File.expand_path('fun.o')
callback :incoming_rpc, [:string], :string
attach_function :do_some_work, [:incoming_rpc, :string], :string, blocking: true
def initialize
@callback = build_callback_runner
output = do_some_work(@callback, "Ruby init...")
puts "Output: #{output.inspect}"
end
def build_callback_runner
FFI::Function.new(:string, [:string]) do |name|
puts "Inside runner: #{name}"
"DO YOU READ ME?"
end
end
end
Foo.new
这是我正在调用的C函数:是的,我知道它不是出色的C,我的原始接收器正在运行中,它也以完全相同的方式失败。(我也不保证会写出精彩的作品)
// Name: fun.c
// Compiled with: gcc -shared -o fun.o fun.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char* (*callbkfn)(char*);
extern char* do_some_work(callbkfn fn, char* name);
char* do_some_work(callbkfn fn, char* userdata) {
printf("do_some_work param: %s\n", userdata);
printf("callback output: %s\n", fn(strdup("Hello from C")));
return strdup("Returned from C");
}
输出:
do_some_work param: Ruby init...
Inside runner: Hello from C
callback output: (null)
Output: "Returned from C"
回调输出中的null似乎无法动摇。如何将回调FFI :: Function或回调proc的“返回”值传递回C?FFI文档似乎总是将callback设置为:void
,我猜答案在指针页面上的某处-但是我在绘制空白(很像我的回调)
如果使用a:pointer
作为返回类型而不是:string
(char
无论如何只是一个指针),就可以使它起作用:
class Foo
extend FFI::Library
ffi_lib File.expand_path('fun.o')
callback :incoming_rpc, [:string], :pointer # <- change here
attach_function :do_some_work, [:incoming_rpc, :string], :string, blocking: true
def initialize
@callback = build_callback_runner
output = do_some_work(@callback, "Ruby init...")
puts "Output: #{output.inspect}"
end
def build_callback_runner
FFI::Function.new(:pointer, [:string]) do |name| # <- and here
puts "Inside runner: #{name}"
FFI::MemoryPointer.from_string("DO YOU READ ME?") # <- and here
end
end
end
Foo.new
使用问题中的C代码,将产生:
do_some_work param: Ruby init...
Inside runner: Hello from C
callback output: DO YOU READ ME?
Output: "Returned from C"
主要问题是内存分配和释放。在这种情况下MemoryPointer
,将进行垃圾回收,这将释放字符串数据。我相当确定这是安全的,只要C函数不保存指针并在以后尝试使用它即可(即GC不会在C函数完成之前发生)。如果是这样,您将需要确保该函数复制了该字符串,或者研究了包装和使用malloc
andfree
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句