当前位置: 首页 > 面试题库 >

使用SWIG与数组进行交互的正确方法

花高爽
2023-03-14
问题内容

我对swig中的typemap和如何使用数组感到迷茫。我准备了一个使用swig在java和c之间使用数组的工作示例,但是我不知道这是否是正确的方法。

基本上,我想将字节数组byte[]从Java 传递给c作为“ signed char *”
+它的大小,在c中对其进行修改并查看java中的更改,并在c中创建一个数组并在Java中使用它。

*在C中被修改为Java或其他的缓冲区?](http://codingdict.com/questions/134119)

并且实际上以解决方案为例进行了指导。

这是我在arrays.h文件中的代码:

#include <iostream>

bool createArray(signed char ** arrCA, int * lCA){
    *lCA = 10;
    *arrCA = (signed char*) calloc(*lCA, sizeof(signed char));

    for(int i = 0; i < *lCA; i++){
        (*arrCA)[i] = i;
    }

    return *arrCA != NULL;
}

bool readArray(const signed char arrRA[], const int lRA){
    for(int i = 0; i < lRA; i++){
        std::cout << ((unsigned int) arrRA[i]) << " ";
    }
    std::cout << std::endl;
    return true;
}

bool modifyArrayValues(signed char arrMA[], const int lMA){
    for(int i = 0; i < lMA; i++){
        arrMA[i] = arrMA[i] * 2;
    }
    return true;
}


bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){

    *lMALOut = 5;
    *arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));

    for(int i = 0; i < *lMALOut; i++){
        (*arrMALOut)[i] = arrMALIn[i];
    }
    return true;
}

这是swig(.arrays.i)的.i文件:

%module arrays

%{
    #include "arrays.h"
%}

%typemap(jtype) bool createArray "byte[]"
%typemap(jstype) bool createArray "byte[]"
%typemap(jni) bool createArray "jbyteArray"
%typemap(javaout) bool createArray { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrCA (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lCA (int l) "$1=&l;"
%typemap(argout) (signed char ** arrCA, int * lCA) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool createArray {
    if (!$1) {
        return NULL;
    }
}


%typemap(jtype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jstype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jni) (const signed char arrRA[], const int lRA) "jbyteArray"
%typemap(javain) (const signed char arrRA[], const int lRA) "$javainput"

%typemap(in,numinputs=1) (const signed char arrRA[], const int lRA) {
  $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
  $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (const signed char arrRA[], const int lRA) {
  // Or use  0 instead of ABORT to keep changes if it was a copy
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}


%typemap(jtype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jstype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jni) (signed char arrMA[], const int lMA) "jbyteArray"
%typemap(javain) (signed char arrMA[], const int lMA) "$javainput"

%typemap(in, numinputs=1) (signed char arrMA[], const int lMA) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMA[], const int lMA) {
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, 0); 
}

%typemap(jtype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jstype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jni) (signed char arrMALIn[], int lMALIn) "jbyteArray"
%typemap(javain) (signed char arrMALIn[], int lMALIn) "$javainput"

%typemap(in, numinputs=1) (signed char arrMALIn[], int lMALIn) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMALIn[], int lMALIn) {
    JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}

%typemap(jtype) bool modifyArrayLength "byte[]"
%typemap(jstype) bool modifyArrayLength "byte[]"
%typemap(jni) bool modifyArrayLength "jbyteArray"
%typemap(javaout) bool modifyArrayLength { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrMALOut (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lMALOut (int l) "$1=&l;"
%typemap(argout) (signed char ** arrMALOut, int * lMALOut) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool modifyArrayLength {
    if (!$1) {
        return NULL;
    }
}


%include "arrays.h"

最后是Java代码对其进行测试:

public class Run{

    static {
        System.loadLibrary("Arrays");
    }

    public static void main(String[] args){

        byte[] test = arrays.createArray();

        printArray(test);

        arrays.readArray(test);

        arrays.modifyArrayValues(test);

        printArray(test);

        byte[] test2 = arrays.modifyArrayLength(test);

        printArray(test2);

    }

    private static void printArray(byte[] arr){

        System.out.println("Array ref: " + arr);

        if(arr != null){
            System.out.println("Array length: " + arr.length);

            System.out.print("Arrays items: ");

            for(int i =0; i < arr.length; i++){
                System.out.print(arr[i] + " ");
            }
        }
        System.out.println();
    }
}

该示例有效,但是我不确定那是正确的方法,我的意思是:

有没有更简单的方法来达到相同的结果?

此代码是否存在内存泄漏(一方面,我认为是因为我执行了calloc,但没有释放它,但另一方面,我将其传递给了SetByteArrayRegion,因此释放它可能会导致错误)?

SetByteArrayRegion是否仅复制值还是仅复制引用?例如,如果不是实际执行calloc,而是如果通过引用从c
++对象获取一个数组,该数组将在退出作用域时销毁,该怎么办?

使Java返回的数组无效时,数组是否正确释放?

有没有一种方法可以指定类型映射从何处应用到哪里?,我的意思是,在.i代码中,我为每个函数都提供了一个类型映射,我认为我可以在其中重用其中的一些,但是如果还有其他具有相同功能的函数我不想对它们进行参数映射的参数,该怎么办,我可能无法修改函数的参数名称。

我已经看到了这个问题中描述的carrays.i可能性。如何使用Swig 将数组从Java传递到C++?,但这意味着如果数组的大小为1000个项目,并且我想通过Java套接字发送它或从中创建一个字符串,则我必须为每个数组项目进行1次JNI调用。而且我实际上希望
byte[] 在Java端提供一个而不是一组函数来访问底层数组,因此,现有代码无需修改即可工作。

上下文:我要实现此目标的原因是,有一个具有某些功能的库,但重要的是它允许使用Google协议缓冲区从库中导入和导出数据。因此,与此问题相关的代码如下所示:

class SomeLibrary {

  bool export(const std::string & sName, std::string & toExport);

  bool import(const std::string & sName, const std::string & toImport);

}

事实是,C ++中的Protobuf使用std :: string来存储数据,但是该数据是二进制的,因此由于其被截断而不能作为普通Java
String返回,在Swig中更多:转换返回类型std ::: string(binary)到javabyte

所以我的想法是返回Java abyte[]来进行序列化的Protobuf(与Java版本的Protocol缓冲区一样)并接受byte[]解析protobuf的操作。为了避免进入SWIGTYPE_p_std_stringexport的第二个参数,并为import
y的第二个参数使用String,使用%extend包装了两个函数,如下所示:

%extend SomeLibrary{

  bool export(const std::string & sName, char ** toExportData, int * toExportLength);

  bool import(const std::string & sName, char * toImportData, int toImportLength);

}

现在,我应该能够制作出类型图。

但为了更一般的,我要求一般从Java操作数组痛饮的, 具有 原生的Java byte[]


问题答案:

不要自动打折carrays.i。也就是说,SWIG已经有了一些方便的类型映射:

%module test

%apply(char *STRING, size_t LENGTH) { (char *str, size_t len) };

%inline %{
void some_func(char *str, size_t len) {
}
%}

它在Java接口中产生一个函数:

public static void some_func(byte[] str)

也就是说,它需要一个可以像普通一样在Java中构建的数组,并为您填充指针和长度。几乎免费。

几乎可以肯定的是,您的代码会泄漏-您希望free()在argout类型映射中调用,以在将分配的内存复制到新的Java数组后释放释放的内存。

您可以通过参数的类型
名称来选择性地应用类型图。有关类型映射匹配规则的更多信息,请参见本文档。您还可以请求显式地使用typemap,否则将无法%apply如我在上面的示例中那样使用它。(实际上,它会复制类型图,因此,如果您仅修改其中之一,则一般情况下不会替换它)

通常,用于数组从Java到C 或使用已知大小的数组的类型映射要比从C 返回到Java的类型映射更简单,因为大小信息更加明显。

我的建议是计划在Java内部进行大量分配工作,并设计可能会使数组增长以两种模式操作的函数:一种指示所需的大小,另一种实际完成工作。您可以这样做:

ssize_t some_function(char *in, size_t in_sz) {
  if (in_sz < the_size_I_need) {
    return the_size_I_need; // query the size is pretty fast
  }

  // do some work on in if it's big enough

  // use negative sizes or exceptions to indicate errors

  return the_size_I_really_used; // send the real size back to Java
}

这将使您可以在Java中执行以下操作:

int sz = module.some_function(new byte[0]);
byte result[] = new byte[sz];
sz = module.some_function(result);

请注意,使用默认的typemap new byte[0]是必需的,因为它们不允许null用作数组-
如果需要,您可以添加允许使用此类型的typemap,或者用于%extend提供不需要空数组的重载。



 类似资料:
  • 我对swig中的类型映射以及如何使用数组有点迷茫。我已经准备了一个使用swig在java和c之间使用数组的工作示例,但我不知道这是否是正确的方法。 基本上,我想把一个字节数组作为“有符号字符*”的大小从java传递到c,在c中修改它,查看java中的变化,在c中创建一个数组,并在java中使用它。 我已经研究了这些问题:如何使用Swig将数组(java中的long数组)从java传递到C,将数组作

  • 介绍 如果我们为了与合约进行(测试)交互而向每次都向以太坊网络进行原始请求,我们很快就会意识到编写这些请求是笨重而繁琐的。 同样,我们可能会发现管理每个请求的状态是 复杂的。 幸运的是,Truffle为我们处理这种复杂性,使我们与合约的互动变得轻而易举。 数据的读和写 以太坊网络区分将数据写入网络和从网络读取数据,在编写应用程序我们需要关注这个区别。 通常,写入数据称为交易 transaction

  • 本章包含了许多可以在Python使用原生代码(主要是C/C++)方式的介绍,这个过程通常被称为封装。本章的目的是给你有哪些技术存在已经各自有优劣式的一点儿感觉,这样你可以根据你的具体需求选择适合的方式。无论如何,只要你开始做封装,你几乎都必然需要咨询你选定技术的文档。 2.8.1 简介 本章将涵盖一下技术: Python-C-Api Ctypes SWIG (简化封装器和接口生成器) Cython

  • 本文向大家介绍使用django和vue进行数据交互的方法步骤,包括了使用django和vue进行数据交互的方法步骤的使用技巧和注意事项,需要的朋友参考一下 一、前端请求的封装 1.将请求地址封装起来,以便日后修改,在src/assets/js目录下创建getPath.js文件 2.在同一个目录下创建axios.js文件 我的前端数据交互使用的模块使用的是axios 二、前端Get请求使用 1.在s

  • 问题内容: 我正在帮助别人使用他的JavaScript代码,但我的眼睛被一段看起来像这样的部分所吸引: 我的第一个想法是: 嘿,这可能行不通! 但是后来我做了一些实验,发现它确实确实至少提供了很好的随机结果。 但是我的直觉告诉我,这一定是错误的。特别是由于ECMA标准未指定排序算法。我认为不同的排序算法将导致不同的不均匀混洗。一些排序算法甚至可能无限循环… 但是你觉得呢? 还有另一个问题……我现在

  • 本文向大家介绍使用JavaScript Array.sort()方法进行改组是否正确?,包括了使用JavaScript Array.sort()方法进行改组是否正确?的使用技巧和注意事项,需要的朋友参考一下 是的,您可以使用JavaScript Array.sort()方法进行改组。让我们看看 示例