JNR 采用指针参数的回调/闭包
Posted
技术标签:
【中文标题】JNR 采用指针参数的回调/闭包【英文标题】:Callback/closure with JNR taking a pointer argument 【发布时间】:2014-10-05 04:02:37 【问题描述】:我正在使用 JNR 并尝试使用以下 C 等效签名传递回调函数:
int fn(void const*, void const**, void**)
进入一些 C 函数。我已将嵌套在 Java 端的 JNR 库接口中的回调声明为:
public static interface Fn
@Delegate public int call(Pointer a, Pointer[] b, Pointer[] c);
与 JNR 库接口中的另一个函数
public int doSomething(Fn fn);
在接受int(*)(void const*, void const**, void**)
的C 代码中充当doSomething
的包装器。但是每当我创建回调时:
new Fn() int call() ... ;
并将其传递给我的 JNR 库接口的 doSomething
方法,我得到运行时错误:
java.lang.ExceptionInInitializerError
Caused by:
java.lang.IllegalArgumentException: unsupported closure parameter type class [Ljnr.ffi.Pointer;
at jnr.ffi.provider.jffi.NativeClosureProxy.newProxyFactory(NativeClosureProxy.java:109)
at jnr.ffi.provider.jffi.NativeClosureFactory.newClosureFactory(NativeClosureFactory.java:84)
at jnr.ffi.provider.jffi.NativeClosureManager.initClosureFactory(NativeClosureManager.java:71)
at jnr.ffi.provider.jffi.NativeClosureManager.getClosureFactory(NativeClosureManager.java:49)
at jnr.ffi.provider.jffi.NativeClosureManager.newClosureSite(NativeClosureManager.java:81)
at jnr.ffi.provider.jffi.InvokerTypeMapper.getToNativeConverter(InvokerTypeMapper.java:68)
at jnr.ffi.provider.jffi.InvokerTypeMapper.getToNativeType(InvokerTypeMapper.java:143)
at jnr.ffi.mapper.CachingTypeMapper.lookupAndCacheToNativeType(CachingTypeMapper.java:71)
at jnr.ffi.mapper.CachingTypeMapper.getToNativeType(CachingTypeMapper.java:43)
at jnr.ffi.mapper.CompositeTypeMapper.getToNativeType(CompositeTypeMapper.java:34)
at jnr.ffi.provider.jffi.InvokerUtil.getParameterTypes(InvokerUtil.java:185)
at jnr.ffi.provider.jffi.AsmLibraryLoader.generateInterfaceImpl(AsmLibraryLoader.java:125)
at jnr.ffi.provider.jffi.AsmLibraryLoader.loadLibrary(AsmLibraryLoader.java:59)
at jnr.ffi.provider.jffi.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:43)
at jnr.ffi.LibraryLoader.load(LibraryLoader.java:265)
at jnr.ffi.LibraryLoader.load(LibraryLoader.java:244)
我使用 Pointer
有什么问题?
【问题讨论】:
发现这个:github.com/jnr/jnr-ffi/blob/master/src/main/java/jnr/ffi/… 不管什么原因,Pointer 数组在某个时候被支持,然后被注释掉了。或者它们是一个想法并在实施之前被注释掉?还是什么? 无论如何,目前正在废弃[]
s,只是通过get
方法通过指针参数访问指针元素...
【参考方案1】:
如果是 C 调用 Java,我认为不可能只用一个 C 指针给 Java 一个实际的 Java 数组。
首先,Java 数组对象具有内置长度,但 C 指针值本身不包含上限。 C 通常使用诸如以零结尾的字符串或传递两个参数(ptr、len)之类的约定。
其次,必须在使用之前填充 Java 数组(即不懒惰)。这意味着加载所有指向数组的指针,这可能效率低下。这也需要使用已知的数组长度来完成。
我建议在访问指向数组的指针时自己在 Java 中进行指针运算。这需要了解特定于平台的内存布局(例如,指针数组中一个指针元素的长度),但所有本机接口都是特定于平台的。
【讨论】:
【参考方案2】:正如wks 所说,
首先,Java 数组对象具有内置长度,但 C 指针值本身不包含上限。 C 通常使用诸如以零结尾的字符串或传递两个参数(ptr、len)之类的约定。
其次,必须在使用之前填充 Java 数组(即不懒惰)。这意味着加载所有指向数组的指针,这可能是低效的。这也需要使用已知的数组长度来完成。
一旦void const**
和void**
参数等价于未知大小 的数组,您应该对这些参数使用jnr.ffi.byref.PointerByReference
,如下所示:
public int call(Pointer a, PointerByReference b, PointerByReference c);
那么你的方法的用法应该是这样的:
Pointer a = new Pointer.wrap(Runtime.getSystemRuntime(), variable);
PointerByReference b = new PointerByReference();
PointerByReference c = new PointerByReference();
call(a, b, c);
Pointer bValue = b.getValue();
要进一步管理数据,您应该确切地知道您正在处理的数据类型。
【讨论】:
以上是关于JNR 采用指针参数的回调/闭包的主要内容,如果未能解决你的问题,请参考以下文章