如何在SWIG生成的Java绑定中转换为SWIGTYPE_p_void类型?

j b*_*j b 5 c java java-native-interface swig

我正在为C库开发一些SWIG生成的Java绑定.该库包含带参数类型的函数void *.上C面这些将通常作为指针类型的数组被传递floatint流延到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.请注意,argvconst void *与不是void *.

Fle*_*exo 3

这个答案还有一个替代方案,它非常不同,并且为这个问题提供了更自然的解决方案,更接近您最初寻找的内容。其他建议集中在添加重载(繁琐的手动)或使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 **)&map;
  (*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 **)&map;
  (*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),然后使用它来进行调用并在调用成功或失败后进行清理。