gpt4 book ai didi

java - SWIG支持void * C返回类型

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:24:18 24 4
gpt4 key购买 nike

我的SWIG接口文件(包含在头文件中)中有一个C函数,该函数当前返回一个char *,SWIG使用该char *为fetchFromRow方法生成String Java返回类型。我想知道是否将C端的返回值更改为void *,SWIG在Java端会做什么? C fetchFromRow函数返回一个结构(sockaddr_in),String或int。如何设置我的SWIG接口文件来支持此功能?有没有一种方法可以使生成的Java fetchFromRow具有Object的返回类型,以便我可以在Java方面进行强制转换?

C代码:

extern char *
fetchFromRow(struct row_t *r_row,
type_t type);

extern void *
fetchFromRow(struct row_t *r_row,
type_t type);

当我使用头文件(包含在SWIG接口文件中)中的void *生成方法时,我得到了带有SWIGTYPE_p_void返回类型的Java方法。关于如何处理的任何想法?

Swig文件:
%module Example
%include "typemaps.i"
%include "stdint.i"
%include "arrays_java.i"
void setPhy_idx(uint32_t value);
%include "arrays_java.i"
void setId(unsigned char *value);
%{
#include "Example1.h"
#include "Example2.h"
#include "Example3.h"
#include "Example4.h"
%}
%rename setLogFile setLogFileAsString;
%inline %{
void setLogFileAsString(const char *fn) {
FILE *f = fopen(fn, "w");
setLogFile(f);
}
%}
%typemap(jstype) void* "java.lang.Object"
%typemap(javaout) void* {
long cPtr = $jnicall;
Object result = null;
if (type == type_t.TYPE_CATEGORY) {
result = void2int8(cPtr);
}
return result;
}

%newobject fetch(struct result_row_t *result_row, type_t type, int32_t *length);
%inline %{

uint8_t void2int8(jlong v) {
return (intptr_t)v;
}

%}
%apply char * { unsigned char * };
%apply char * { const void * }
%apply int32_t { int32_t * }
int createKey(const void* secret, int secret_len, const sdr_id_t *id, unsigned char key[20], int key_len);
session_t* createSession(const char* addr, int ort, const char *ddr, int rt, const der_id_t *id, unsigned char key[20], int key_len);
%apply int32_t *OUTPUT { int32_t *length }
%ignore createKey;
%ignore setLogFile;
%ignore ecreateSession;
%include "Example1.h"
%include "Example2.h"
%include "Example3.h"
%include "Example4.h"
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("Example");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

调用fetch的Java代码:
{
//only type_t param shown here for simplicity
Object category = Example.fetch(result_row, type_t.TYPE_CATEGORY, length);
System.out.println("category=" + aLevel.toString());
System.out.println("category=" + ((Short)aLevel).intValue());
System.out.println("category=" + ((Short)aLevel).toString());
//all 3 Sys outs show same value but when called again each show same value but different than the first execution
}

我正在尝试用SWIG替换的C代码包装器。这种用法是从Java调用的,但是现在我试图直接调用fetch(伪代码):
char *
wrapFetch(struct row_t *result_row, type_t type)
{
int8_t *int8_valp = NULL;
switch (attribute) {
case TYPE_CATEGORY:

int8_valp = fetch(
result_row, attribute, &length);
if (length > 0 && int8_valp != NULL) {
snprintf(smallbuf, sizeof(smallbuf), "%u", *int8_valp);
return strdup(smallbuf);
} else {
return NULL;
}
}

最佳答案

如果您为返回类型定义类型层次结构,并将基类用作fetchFromRow的返回类型,则这可能会更容易。 (事实证明,解决方案并不像我最初想象的那么容易,甚至还有an example in the documentation!This question also applies to Java+SWIG。)尽管您可以按照自己的要求做,但我还是举了一个简单的例子来说明要点。

我在这里使用的示例在test.h中有一个简单的接口(声明和定义使这里的内容更简单):

struct type1 {
type1(int foo) : foo(foo) {}
int foo;
};

struct type2 {
type2(double bar) : bar(bar) {}
double bar;
};

// TYPE3 is int32_t, TYPE4 is const char*

typedef enum { TYPE1, TYPE2, TYPE3, TYPE4 } type_t;

void* fetch(type_t type) {
switch(type) {
case TYPE1:
return new type1(101);
case TYPE2:
return new type2(1.111);
case TYPE3:
return (void*)(-123); // One way of returning int32_t via void*!
case TYPE4:
return (void*)("Hello world"); // Cast because not const void*
default:
return NULL;
}
}

在这里,我们有四种不同的类型,与 enum值配对。为简单起见选择了这些。只要您具有可以应用的合适的类型映射,它们就可以是您想要的任何东西。 (如果要专门使用 sockaddr_in,则应应用 my answer to your previous question中的类型映射,以专门包装 sockaddr_in)。

还有一个函数 fetch,它创建一种类型并通过 void *返回它。这说明了您在问题中提出的要求。 fetch的棘手之处在于,SWIG没有直接的方法来推断 void*指针返回之前的内容。我们需要使用有关 type_t参数含义的高级知识,为SWIG提供一种更具体地了解类型是什么的方法。

要对此进行包装,我们需要一个SWIG接口文件 test.i,该文件以常用的模块材料开头:
%module test
%{
#include "test.h"
%}

为了包装 fetch函数,我们需要找到一种明智的方式来在Java端公开最接近 void*的东西。在这种情况下,我认为 java.lang.Object是返回类型的一个不错的选择,它在这里可以很好地近似 void*
%typemap(jstype) void* "java.lang.Object"

这将设置Java端 fetch的返回类型。 (尽管我们没有使用 %typemap(jtype)更改生成的JNI中介的返回类型,但仍然像以前一样默认为 long)。

接下来,我们需要编写另一个typemap来指定实际调用的结果将如何转换为我们所说的调用将在Java端返回的类型:
%typemap(javaout) void* {
long cPtr = $jnicall;
Object result = null;
if (type == type_t.TYPE1) {
result = new type1(cPtr, $owner);
}
else if (type == type_t.TYPE2) {
result = new type2(cPtr, $owner);
}
else if (type == type_t.TYPE3) {
result = void2int(cPtr);
// could also write "result = new Integer(void2int(cPtr));" explicitly here
}
else if (type == type_t.TYPE4) {
result = void2str(cPtr);
}

return result;
}

%newobject fetch(type_t type);

在这里,我们将创建一个具有合适的SWIG代理类型的Java对象,或者调用一个不久将看到的助手函数。我们通过查看调用中使用的 type_t来决定使用哪种类型。 (我不是100%满意地通过名称来引用此类型,即直接使用 type,但似乎没有更好的方法来访问在 javaout typemap中调用函数的参数)

每个构造函数的第二个参数(这里称为 $owner)对于内存管理很重要,它指出谁拥有分配,并且我们希望将所有权转让给Java以避免泄漏。它的值由 %newobject指令确定。

我们需要一个辅助函数,将 void*转换为 int32_tString案例的更有意义的类型。我们为此提供 %inline,以要求SWIG同时包装和定义它:
%inline %{
int32_t void2int(jlong v) {
return (intptr_t)v;
}

const char *void2str(jlong v) {
return (const char*)v;
}
%}

我在这里使用 jlong是因为在接口的Java端,所有指针都表示为 long。它可以确保函数与JNI调用返回的函数完全兼容,而不会失去精度(在某些平台上 jlong可能是 long long)。基本上,存在这些函数可以通过较少的手动工作来实现从通用( void*)到C端的特定转换。 SWIG在这里为我们处理所有类型。

最后,我们为头文件添加了 %include(我们希望将其包装起来,这是最简单的方法),以及一些导致库自动加载的代码:
%include "test.h"

%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("test");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

我通过编译测试了这种包装:
swig -Wall -java -c++ test.i
javac *.java
g++ -Wall -Wextra test_wrap.cxx -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux/ -o libtest.so

并运行以下Java代码以对其进行“锻炼”。
public class main {
public static void main(String[] argv) {
Object o1 = test.fetch(type_t.TYPE1);
Object o2 = test.fetch(type_t.TYPE2);
Object o3 = test.fetch(type_t.TYPE3);
Object o4 = test.fetch(type_t.TYPE4);

if (!(o1 instanceof type1)) {
System.out.println("Wrong type - o1");
}
else {
System.out.println("o1.getFoo(): " + ((type1)o1).getFoo());
}

if (!(o2 instanceof type2)) {
System.out.println("Wrong type - o2");
}
else {
System.out.println("o2.getFoo(): " + ((type2)o2).getBar());
}

if (!(o3 instanceof Integer)) {
System.out.println("Wrong type - o3");
}
else {
System.out.println("o3.intValue(): " + ((Integer)o3).intValue());
}

if (!(o4 instanceof String)) {
System.out.println("Wrong type - o4");
}
else {
System.out.println("o4: " + (String)o4);
}
}
}

您始终可以从此处显示的代码重新创建整个示例,依次显示并讨论了 test.i,但是为了方便起见,我还放置了 test.i on my site的副本。

关于java - SWIG支持void * C返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8173497/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com