栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

将数组作为指针+大小或范围传递给包装函数

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

将数组作为指针+大小或范围传递给包装函数

关键是要包装这两个函数,您将需要使用多参数typemap。

序言是SWIG的相当标准。我使用了我个人最喜欢的prgama来自动加载共享库,而界面的用户则无需知道:

%module test%{#include "test.hh"%}%pragma(java) jniclasspre=%{  static {    try {        System.loadLibrary("test");    } catch (UnsatisfiedlinkError e) {      System.err.println("Native pre library failed to load. n" + e);      System.exit(1);    }  }%}

首先,尽管您将需要使用一些Java类型映射来指示SWIG

byte[]
用作Java接口的两个部分的类型-JNI和调用它的包装器。在generate模块文件中,我们将使用JNI类型
jbyteArray
。我们将输入直接从SWIG接口传递到它生成的JNI。

%typemap(jtype) (const signed char *arr, size_t sz) "byte[]"%typemap(jstype) (const signed char *arr, size_t sz) "byte[]"%typemap(jni) (const signed char *arr, size_t sz) "jbyteArray"%typemap(javain) (const signed char *arr, size_t sz) "$javainput"

完成后,我们可以编写一个多参数类型映射:

%typemap(in,numinputs=1) (const signed char *arr, size_t sz) {  $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);  $2 = JCALL1(GetArrayLength, jenv, $input);}

intypemap的工作是将JNI调用给出的内容转换为实际函数真正希望作为输入的内容。我曾经

numinputs=1
指出两个实函数参数在Java端仅接受一个输入,但是无论如何这都是默认值,因此不需要明确声明。

在此typemap中,

$1
是typemap
的第一个参数,即本例中函数的第一个参数。我们通过请求指向Java数组的底层存储的指针(实际上可能是副本,也可能不是副本)来进行设置。我们将
$2
第二个typemap参数设置为数组的大小。

JCALLn
此处的宏确保类型图可以同时使用C和C ++ JNI进行编译。它扩展为对语言的适当调用。

一旦实函数调用返回,我们需要另一个类型图进行清理:

%typemap(freearg) (const signed char *arr, size_t sz) {  // Or use  0 instead of ABORT to keep changes if it was a copy  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); }

这需要

ReleaseByteArrayElements
告诉JVM我们已经完成了数组操作。它需要指针
我们从中获得指针的Java数组对象。此外,它需要一个参数,指示内容是否应被复制回 当且仅当
他们进行了修改,我们得到的指针是摆在首位的副本。(我们传递给NULL的参数是指向的可选指针,
jboolean
它指示是否已获得副本)。

对于第二个变体,类型映射基本上相似:

%typemap(in,numinputs=1) (const signed char *begin, const signed char *end) {  $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);  const size_t sz = JCALL1(GetArrayLength, jenv, $input);  $2 = $1 + sz;}%typemap(freearg) (const signed char *begin, const signed char *end) {  // Or use  0 instead of ABORT to keep changes if it was a copy  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT);}%typemap(jtype) (const signed char *begin, const signed char *end) "byte[]"%typemap(jstype) (const signed char *begin, const signed char *end) "byte[]"%typemap(jni) (const signed char *begin, const signed char *end) "jbyteArray"%typemap(javain) (const signed char *begin, const signed char *end) "$javainput"

唯一的区别是使用局部变量

sz
end
使用
begin
指针计算延展性。

剩下要做的唯一一件事就是告诉SWIG使用我们刚刚编写的类型映射来包装头文件本身:

%include "test.hh"

我使用以下命令测试了这两个功能:

public class run {  public static void main(String[] argv) {    byte[] arr = {0,1,2,3,4,5,6,7};    System.out.println("Foo:");    test.foo(arr);    System.out.println("Bar:");    test.bar(arr);  }}

哪个按预期工作。

为方便起见,我分享我在写这本使用的文件我的网站。通过依次遵循此答案,可以重建该存档中每个文件的每一行。


作为参考,我们可以在没有任何JNI调用的情况下完成整个过程,使用它

%pragma(java)modulepre
来生成一个重载,然后使用重载将输入(在纯Java中)转换为实际函数期望的形式。为此,模块文件将是:

%module test%{#include "test.hh"%}%include <carrays.i>%array_class(signed char, ByteArray);%pragma(java) modulepre = %{  // Overload foo to take an array and do a copy for us:  public static void foo(byte[] array) {    ByteArray temp = new ByteArray(array.length);    for (int i = 0; i < array.length; ++i) {      temp.setitem(i, array[i]);    }    foo(temp.cast(), array.length);    // if foo can modify the input array we'll need to copy back to:    for (int i = 0; i < array.length; ++i) {      array[i] = temp.getitem(i);    }  }  // How do we even get a SWIGTYPE_p_signed_char for end for bar?  public static void bar(byte[] array) {    ByteArray temp = new ByteArray(array.length);    for (int i = 0; i < array.length; ++i) {      temp.setitem(i, array[i]);    }    bar(temp.cast(), make_end_ptr(temp.cast(), array.length));    // if bar can modify the input array we'll need to copy back to:    for (int i = 0; i < array.length; ++i) {      array[i] = temp.getitem(i);    }  }%}// Private helper to make the 'end' pointer that bar expects%javamethodmodifiers make_end_ptr "private";%inline {  signed char *make_end_ptr(signed char *begin, int sz) {    return begin+sz;  }}%include "test.hh"%pragma(java) jniclasspre=%{  static {    try {        System.loadLibrary("test");    } catch (UnsatisfiedlinkError e) {      System.err.println("Native pre library failed to load. n" + e);      System.exit(1);    }  }%}

除了将数据转换为正确类型所需的显而易见的(两个)副本(没有简单的方法可以从

byte[]
SWIGTYPE_p_signed_char
),然后将其返回还存在另一个缺点-
它特定于函数
foo
bar
,而我们先前编写的类型映射并不特定于给定的函数-
如果碰巧有一个采用两个范围或两个指针+长度组合的函数,它们将在匹配的任何位置应用,甚至多次应用于同一函数。这样做的一个好处是,如果碰巧有其他包装的函数可以给您
SWIGTYPE_p_signed_char
回馈,那么您仍然可以根据需要使用重载。即使在您有一个
ByteArray
from
的情况下,您
%array_class
仍然无法执行生成Java所需的Java指针算法
end
为了你。

所示的原始方法在Java中提供了更简洁的界面,并具有不产生过多副本和更可重用的附加优点。


包装的另一种替代方法是

%inline
foo
和编写一些重载
bar

%inline {  void foo(jbyteArray arr) {    // take arr and call JNI to convert for foo  }  void bar(jbyteArray arr) {    // ditto for bar  }}

这些在Java接口中以重载形式表示,但是它们仍然是特定于模块的,此外,此处所需的JNI比原本需要的更为复杂-
您需要安排以

jenv
某种方式掌握这些内容,而这些内容无法通过默认。这些选项是调用它的缓慢调用,或者是
numinputs=0
自动填充参数的类型映射。无论哪种方式,多参数类型映射都看起来更好。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/573737.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号