j b*_*j b 5 c java java-native-interface swig
我正在为C库开发一些SWIG生成的Java绑定.该库包含带参数类型的函数void *.上C面这些将通常作为指针类型的数组被传递float或int流延到void *.在生成的Java绑定中,这会产生采用类型参数的方法SWIGTYPE_p_void.
在Java绑定中构造浮点数/整数数组的最佳方法是什么,以便它们可以作为类型传递SWIGTYPE_p_void给这些方法?
目前我正在我的example.i文件中定义一个辅助函数:
void *floata_to_voidp(float f[])
{
return (void *)f;
}
Run Code Online (Sandbox Code Playgroud)
然后在Java端做这样的事情:
float foo[] = new float[2];
SWIGTYPE_p_void av = null;
// do something with foo
av = example.floata_to_voidp(foo);
example.myfunction(av);
Run Code Online (Sandbox Code Playgroud)
这看起来相当丑陋,特别是因为我想inta_to_voidp()在SWIG接口文件中为我想要支持的每种类型转换都需要一个等等.
有没有办法在没有辅助函数的情况下执行此操作,并且在Java端涉及更少的额外代码来转换数据类型?
更新(2012年6月17日):给出问题的更多细节:我要做的是采用一组C函数,使用原型int foo(const float *data, int N, const void *argv, float *result)并将它们映射到Java端的方法,其中任意类型的数组都可以被传递为argv.请注意,argv是const void *与不是void *.
这个答案还有一个替代方案,它非常不同,并且为这个问题提供了更自然的解决方案,更接近您最初寻找的内容。其他建议集中在添加重载(繁琐的手动)或使array_classes 以某种方式实现通用接口。
它忽略的是,在大多数情况下,这在 Java 中Object是一个很好的匹配。void*即使Java 中的数组也是Objects。这意味着,如果您有 SWIG 映射void*,Object它将接受您可能想要传入的任何数组作为输入。稍微小心一点并使用一些 JNI,我们就可以获得指向该数组开头的指针以传递给函数。显然,我们需要拒绝非数组,Object但有例外。
我们最终仍然编写一些(私有)辅助函数来安排提取真正的底层指针并在完成后释放它,但是这个解决方案的好处是我们只需要执行一次,然后我们最终得到一个类型映射可用于任何采用数组的函数,如下所示void*。
我最终为此解决方案提供了以下 SWIG 界面:
%module test
%{
#include <stdint.h>
void foo(void *in) {
printf("%p, %d, %g\n", in, *(jint*)in, *(jdouble*)in);
}
%}
%typemap(in,numinputs=0) JNIEnv *env "$1 = jenv;"
%javamethodmodifiers arr2voidd "private";
%javamethodmodifiers arr2voidi "private";
%javamethodmodifiers freearrd "private";
%javamethodmodifiers freearri "private";
%inline %{
jlong arr2voidd(JNIEnv *env, jdoubleArray arr) {
void *ptr = (*env)->GetDoubleArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearrd(JNIEnv *env, jdoubleArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->ReleaseDoubleArrayElements(env, arr, ptr, JNI_ABORT);
}
jlong arr2voidi(JNIEnv *env, jintArray arr) {
void *ptr = (*env)->GetIntArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearri(JNIEnv *env, jintArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->ReleaseIntArrayElements(env, arr, ptr, JNI_ABORT);
}
%}
%pragma(java) modulecode=%{
private static long arrPtr(Object o) {
if (o instanceof double[]) {
return arr2voidd((double[])o);
}
else if (o instanceof int[]) {
return arr2voidi((int[])o);
}
throw new IllegalArgumentException();
}
private static void freeArrPtr(Object o, long addr) {
if (o instanceof double[]) {
freearrd((double[])o, addr);
return;
}
else if (o instanceof int[]) {
freearri((int[])o, addr);
return;
}
throw new IllegalArgumentException();
}
%}
%typemap(jstype) void *arr "Object"
%typemap(javain,pre=" long tmp$javainput = arrPtr($javainput);",post=" freeArrPtr($javainput, tmp$javainput);") void *arr "tmp$javainput"
void foo(void *arr);
Run Code Online (Sandbox Code Playgroud)
这为两种数组类型实现了它,数量有限,您也可以使用片段或宏来帮助解决这个问题。SWIG 在内部使用 ajlong来表示指针。因此,对于每种数组类型,我们需要一个函数来返回给定数组的指针和另一个函数来释放它。这些是私有的并且是模块类的一部分 - 除了模块之外没有人需要知道它是如何工作的。
然后有两个函数接受Object并使用instanceof(丑陋,但Java中的数组没有任何其他公共基础或接口,并且泛型没有帮助)并调用正确的函数来获取/释放指针。
有了这些,只需两个类型映射即可设置 SWIG 将其用于所有void *arr参数。jstype 类型映射指示 SWIG在这些情况Object下使用void*。javain 类型映射安排一个临时局部变量来保存指针(在 a 中long),然后使用它来进行调用并在调用成功或失败后进行清理。