SWIG 和 Java:如何将指向对象输出参数的指针的 C++ 指针映射到 Java
SWIG and Java: how to map a c++ pointer to pointer to object output parameter to Java
首先,我找了几个匹配的问题,都没有找到满意的答案。其中大部分涵盖了指针到指针的 c 参数(而不是 c++)。还有一些封面Python而不是Java.
我有一个 c++ 方法,它有一个输出参数,它是一个指向对象指针的指针。我想从 Java.
调用这个方法
在 Java 中使用 SWIG 的文档中,我找到了 this Butler example。这几乎是我所需要的,只是它涵盖了结构而不是对象。它也是为 C 而不是 C++ 编写的。我从这个例子开始,认为我需要的可能看起来很像这个例子(也许我需要一种完全不同的方法,但我还是试了一下)。
原始的 C 实现如下所示:
int HireButler(Butler **ppButler) {
Butler *pButler = (Butler *)malloc(sizeof(Butler));
pButler->hoursAvailable = 24;
pButler->greeting = (char *)malloc(32);
strcpy(pButler->greeting, "At your service Sir");
*ppButler = pButler;
return 1;
}
在我的 C++ 版本中,它看起来像这样(我制作了 Butler class 的 HireButler 和 FireButler 静态方法):
class Butler {
// ... necessary class members, getters and setters go here ...
static int HireButler(Butler **ppButler) {
Butler *pButler = new Butler();
pButler->setHoursAvailable(24);
pButler->setGreeting("At your service Sir");
*ppButler = pButler;
return 1;
}
static void FireButler(Butler *pButler) {
delete pButler;
}
};
对于 SWIG 接口文件,我几乎完全复制了示例中的代码。除了我必须将 c 风格的 JNI 调用更改为 c++ 风格的 JNI 调用(所以这是 jenv-> 而不是 (*jenv)-> 并删除第一个参数):
// Do not generate the default proxy constructor or destructor
%nodefaultctor Butler;
%nodefaultdtor Butler;
// Add in pure Java code proxy constructor
%typemap(javacode) Butler %{
/** This constructor creates the proxy which initially does not create nor own any C memory */
public Butler() {
this(0, false);
}
%}
// Type typemaps for marshalling Butler **
%typemap(jni) Butler ** "jobject"
%typemap(jtype) Butler ** "Butler"
%typemap(jstype) Butler ** "Butler"
// Typemaps for Butler ** as a parameter output type
%typemap(in) Butler ** (Butler *ppButler = 0) %{
= &ppButler;
%}
%typemap(argout) Butler ** {
// Give Java proxy the C++ pointer (of newly created object)
jclass clazz = jenv->FindClass("Butler");
jfieldID fid = jenv->GetFieldID(clazz, "swigCPtr", "J");
jlong cPtr = 0;
*(Butler **)&cPtr = *;
jenv->SetLongField($input, fid, cPtr);
}
%typemap(javain) Butler ** "$javainput"
在我使用 SWIG 生成必要的 Java 和 C++ 包装器代码后,所有内容都可以编译并且 Java 代码看起来不错。但是,当我尝试 运行 以下 Java 代码时,出现异常:
Butler jeeves = new Butler();
Butler.HireButler(jeeves);
System.out.println("Greeting: " + jeeves.getGreeting());
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
从错误报告文件来看,异常似乎发生在使用 JNI 检索 swigCPtr 字段时:
Stack: [0x0000000002590000,0x0000000002690000], sp=0x000000000268f630, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [jvm.dll+0x136519]
C [TestDll.dll+0x411f] JNIEnv_::GetFieldID+0x4f
C [TestDll.dll+0x4e05] Java_com_test_exampleJNI_Butler_1HireButler+0x95
C 0x000000000297dcec
不幸的是,我完全没有使用 JNI 的经验,所以我现在很困惑。
这是典型的情况,在我问完问题后我顿时恍然大悟,发现了问题所在。
我需要在 JNI 调用中使用完全限定的 class 名称:
jclass clazz = jenv->FindClass("com/test/Butler");
而不是
jclass clazz = jenv->FindClass("Butler");
首先,我找了几个匹配的问题,都没有找到满意的答案。其中大部分涵盖了指针到指针的 c 参数(而不是 c++)。还有一些封面Python而不是Java.
我有一个 c++ 方法,它有一个输出参数,它是一个指向对象指针的指针。我想从 Java.
调用这个方法在 Java 中使用 SWIG 的文档中,我找到了 this Butler example。这几乎是我所需要的,只是它涵盖了结构而不是对象。它也是为 C 而不是 C++ 编写的。我从这个例子开始,认为我需要的可能看起来很像这个例子(也许我需要一种完全不同的方法,但我还是试了一下)。
原始的 C 实现如下所示:
int HireButler(Butler **ppButler) {
Butler *pButler = (Butler *)malloc(sizeof(Butler));
pButler->hoursAvailable = 24;
pButler->greeting = (char *)malloc(32);
strcpy(pButler->greeting, "At your service Sir");
*ppButler = pButler;
return 1;
}
在我的 C++ 版本中,它看起来像这样(我制作了 Butler class 的 HireButler 和 FireButler 静态方法):
class Butler {
// ... necessary class members, getters and setters go here ...
static int HireButler(Butler **ppButler) {
Butler *pButler = new Butler();
pButler->setHoursAvailable(24);
pButler->setGreeting("At your service Sir");
*ppButler = pButler;
return 1;
}
static void FireButler(Butler *pButler) {
delete pButler;
}
};
对于 SWIG 接口文件,我几乎完全复制了示例中的代码。除了我必须将 c 风格的 JNI 调用更改为 c++ 风格的 JNI 调用(所以这是 jenv-> 而不是 (*jenv)-> 并删除第一个参数):
// Do not generate the default proxy constructor or destructor
%nodefaultctor Butler;
%nodefaultdtor Butler;
// Add in pure Java code proxy constructor
%typemap(javacode) Butler %{
/** This constructor creates the proxy which initially does not create nor own any C memory */
public Butler() {
this(0, false);
}
%}
// Type typemaps for marshalling Butler **
%typemap(jni) Butler ** "jobject"
%typemap(jtype) Butler ** "Butler"
%typemap(jstype) Butler ** "Butler"
// Typemaps for Butler ** as a parameter output type
%typemap(in) Butler ** (Butler *ppButler = 0) %{
= &ppButler;
%}
%typemap(argout) Butler ** {
// Give Java proxy the C++ pointer (of newly created object)
jclass clazz = jenv->FindClass("Butler");
jfieldID fid = jenv->GetFieldID(clazz, "swigCPtr", "J");
jlong cPtr = 0;
*(Butler **)&cPtr = *;
jenv->SetLongField($input, fid, cPtr);
}
%typemap(javain) Butler ** "$javainput"
在我使用 SWIG 生成必要的 Java 和 C++ 包装器代码后,所有内容都可以编译并且 Java 代码看起来不错。但是,当我尝试 运行 以下 Java 代码时,出现异常:
Butler jeeves = new Butler();
Butler.HireButler(jeeves);
System.out.println("Greeting: " + jeeves.getGreeting());
System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");
从错误报告文件来看,异常似乎发生在使用 JNI 检索 swigCPtr 字段时:
Stack: [0x0000000002590000,0x0000000002690000], sp=0x000000000268f630, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [jvm.dll+0x136519]
C [TestDll.dll+0x411f] JNIEnv_::GetFieldID+0x4f
C [TestDll.dll+0x4e05] Java_com_test_exampleJNI_Butler_1HireButler+0x95
C 0x000000000297dcec
不幸的是,我完全没有使用 JNI 的经验,所以我现在很困惑。
这是典型的情况,在我问完问题后我顿时恍然大悟,发现了问题所在。
我需要在 JNI 调用中使用完全限定的 class 名称:
jclass clazz = jenv->FindClass("com/test/Butler");
而不是
jclass clazz = jenv->FindClass("Butler");