使用SWIG Directors将数组从C 传递到Java

Passing arrays from C++ to Java using Swig directors, the up call

本文关键字:Java SWIG Directors 数组 使用      更新时间:2023-10-16

我有一个带有虚拟方法的C 类。我正在使用董事,并在Java中属于C 类。此类用于从C 代码接收回调。因此,Java类然后将其传递到其上的C 和C 调用方法(呼叫到Java)。有数组参数(或指针数组,我两者都尝试过),然后将它们转换为swigtype_p_double。

我想拥有一个double []的Java侧类型签名,当然具有该数组的内容在Double []参数中(复制内容很好)。

我该怎么做?

我已经尝试了以下代码,这些代码是我从某些电子邮件列表中提起的:

c_backend.i:

%module(directors="1") c_backend
%{
#include "c_backend.h"
%}
%typemap(directorin, descriptor="[D") (double *DOUBLE, size_t LENGTH) { 
   jdoubleArray jd = (jenv)->NewDoubleArray($2); 
   (jenv)->SetDoubleArrayRegion(jd, 0, $2, (jdouble *)$1); 
   $input = jd; 
} 
%typemap(directorargout) (double *DOUBLE, size_t LENGTH) 
%{(jenv)->GetDoubleArrayRegion($input, 0, $2, (jdouble *)$1); %} 
%feature("director") CallbackHandler;
%include "c_backend.h"

c_backend.h:

#ifndef CALLBACK_HANDLER_H
#define CALLBACK_HANDLER_H
#include <stdio.h>

class CallbackHandler {
  public:
    virtual ~CallbackHandler() {}
    virtual void statusUpdate( double *params, size_t size ) {
        printf("in C++ statusUpdaten");
    }
};

class Server {
  public:
    void doSomething( CallbackHandler * );
};
#endif

c_backend.cpp:

#include "c_backend.h"
#include <stdio.h>
#include <stdlib.h>
void Server::doSomething( CallbackHandler *ch ) {
    double *params = (double *)malloc(3*sizeof(double));
    params[0] = 1.1;
    params[1] = 2.2;
    params[2] = 3.3;
    printf("In doSomthingn");
    ch->statusUpdate(params,3);
    printf("exiting doSomthingn");
}

javafrontend.java:

public class JavaFrontend {
    static {
        System.loadLibrary("CBackend");
    }
    public static void main( String[] args ) {
        JFCallbackHandler jf = new JFCallbackHandler();
        new Server().doSomething(jf);
    }
    public static class JFCallbackHandler extends CallbackHandler {
        public void statusUpdate( double params[], long size ) {
            System.out.println("Java got params: "+params);
        }
    }
}

和一个编译的制作费:

JAVA_INCLUDE=-I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/include/darwin
all:
    c++ -c c_backend.cpp
    swig -java -c++ $(JAVA_INCLUDE) c_backend.i
    c++ $(JAVA_INCLUDE) -c c_backend_wrap.cxx
    c++ -dynamiclib -o libCBackend.jnilib *.o -framework JavaVM
    javac *.java
clean:
    rm -rf *.class *.o *_wrap.cxx *_wrap.h Server.java SWIGTYPE*.java c_backend*.java CallbackHandler.java

swig -version:

SWIG版本3.0.8

用clang 编译[x86_64-apple-darwin15.2.0]

配置的选项: pcre

请参阅http://www.swig.org进行报告,并进一步报告 信息

我付出了一些努力。您发现作为起点的打字是合理的,但我认为不是完整的。我认为您无法实际编写Directorin/Directorargout Typemaps,而无需在/JTYPE/JSTYPE/JNI/JNI/JAVADIRECTORIN/JAVAIN ONE中进行匹配,因为您很快就会迅速在生成代码的各个片段之间遇到不匹配的期望。(主管代码也可以调用常规Java类,也可以通过它来调用)。

另外,我认为最好使用多距离Typemap将指针和大小的尺寸凝结到Java内部的单个参数,因为长度隐含地是Java中一个数组的属性。

因此,这是我必须做的使它起作用的快速摘要:

  1. 首先,您现有的打字不会应用于代码,因为它们在参数类型和参数名称上都匹配。%apply是这样做的整洁方法,尤其是对于这样的多重题词打字。
  2. 其次,添加了相应的打字件,而不仅仅是导演。
  3. 第三,添加了通过代理从C 到Java的 double[]的添加类型。
  4. 最后,由于类型现在仅仅是double[],并且隐含的大小需要更新测试用例,以确保其替代而不是超载。为了好的措施,我添加了@Override

和我进行的一些风格上的更改,因为它们是更好的代码:

  1. 将铸件从键入输入输入到jdouble。充其量它们应该是no -op( double*-> jdouble*),但最糟糕的是,他们会隐藏一些东西。
  2. 将Typemaps设置为自己的街区。这意味着您可以在同一函数上两次使用相同的Typemap,而不会冲突本地变量名称。(尽管我最终都删除了本地变量)
  3. 使用Swig的Jcallx Macros-这显然是C 代码,但这是我在编写Swig代码时尝试保留的习惯。

最终您的swig界面看起来像这样:

%module(directors="1") c_backend
%{
#include "c_backend.h"
%}
%typemap(jstype) (double *DOUBLE, size_t LENGTH) "double[]"
%typemap(jtype) (double *DOUBLE, size_t LENGTH) "double[]"
%typemap(jni) (double *DOUBLE, size_t LENGTH) "jdoubleArray"
%typemap(javadirectorin) (double *DOUBLE, size_t LENGTH) "$jniinput"
%typemap(javain) (double *DOUBLE, size_t LENGTH) "$javainput"
%typemap(in,numinputs=1) (double *DOUBLE, size_t LENGTH) {
  // Note the NULL here if you don't want to be making changes visible
  $1 = JCALL2(GetDoubleArrayElements, jenv, $input, NULL);
  $2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (double *DOUBLE, size_t LENGTH) {
  // Swap 0 for JNI_ABORT if you don't want to make changes visible
  JCALL3(ReleaseDoubleArrayElements, jenv, $input, $1, 0); 
}
%typemap(directorin,descriptor="[D") (double *DOUBLE, size_t LENGTH) { 
  $input = JCALL1(NewDoubleArray, jenv, $2); 
  JCALL4(SetDoubleArrayRegion, jenv, $input, 0, $2, $1); 
} 
%typemap(directorargout) (double *DOUBLE, size_t LENGTH) {
  (jenv)->GetDoubleArrayRegion($input, 0, $2, $1); 
} 
%feature("director") CallbackHandler;
%apply (double *DOUBLE, size_t LENGTH) { (double *params, size_t size) };
%include "c_backend.h"

足以使您的测试案例在上述更改中正确工作以使其覆盖而不是现在超负荷。