0

问题涉及对 C 函数 (API) 的 JAVA 调用,该函数返回一个指向指针的指针作为 argout 参数。我试图从 JAVA 调用 C API,但我无法修改 API。

4

2 回答 2

0

[Swig] Java:使用 C 辅助函数传递指针到指针

  1. 问题涉及对 C 函数 (API) 的 JAVA 调用,该函数返回一个指向指针的指针作为 argout 参数。我试图从 JAVA 调用 C API,但我无法修改 API。

API.h 头文件包含:

extern int ReadMessage(HEADER **hdr);

原始的 C 调用如下所示:

HEADER *hdr;
int status;
status = ReadMessage(&hdr);

API 的功能是将数据存储在指针指定的内存位置。

  1. 我尝试使用 SWIG 创建适当的接口文件。SWIG.i 从 API.h 创建了文件 SWIGTYPE_p_p_header.java。问题是 SWIGTYPE_p_p_header 构造函数将 swigCPtr 初始化为 0。

JAVA 调用看起来像:

SWIGTYPE_p_p_header hdr = new SWIGTYPE_p_p_header();
status = SWIG.ReadMessage(hdr);

但是当我从 JAVA 调用 API 时,ptr 始终为 0。

  1. 我终于放弃了将指针作为输入参数传递。相反,我在 SWIG.i 中定义了另一个 C 函数,以在返回值中返回指向指针的指针。我以为这是一个 Kludge ......但它奏效了!

你可能想试试这个:

SWIG.i 看起来像:

// return pointer-to-pointer
%inline %{
   HEADER *ReadMessageHelper() {
   HEADER *hdr;
   int returnValue;
   returnValue = ReadMessage(&hdr);
   if (returnValue!= 1) hdr = NULL;
   return hdr;
}%}
  1. 上面的内联函数可能会泄漏内存,因为 Java 不会获得 ReadMessageHelper 创建的内存的所有权,因为 HEADER 实例是在堆上创建的。

内存泄漏的修复方法是将 ReadMessageHelper 定义为一个新对象,以便 Java 控制内存。

%newobject ReadMessageHelper();

JAVA 调用现在看起来像:

HEADER hdr;
hdr = SWIG.ReadMessageHelper();
  1. 如果你像我一样幸运的话,你可能有另一个 API 可用于释放消息缓冲区。在这种情况下,您不必执行上一步。

  2. SWIG 大师威廉·富尔顿 (William Fulton) 对上述方法有这样的看法:

“我不认为辅助函数是一个杂物,更像是解决棘手问题的最简单解决方案。考虑 ReadMessage() 的等效纯 100% Java 代码。我不认为 Java 类是通过引用传递的等价物,并且不存在对引用的引用或指向 Java 中指针的指针之类的东西。在您拥有的 C 函数中,一个 HEADER 实例由 ReadMessage 创建并传递回调用者。如果不提供一些围绕 HEADER 的包装类并将包装器传递给 ReadMessage 函数,我看不出如何在 Java 中做同样的事情。归根结底,ReadMessage 返回一个新创建的 HEADER,而 Java 返回新创建对象的方式是在返回值中返回它,而不是通过参数。”</p>

于 2013-03-06T16:24:54.807 回答
0

使用 SWIG 类型映射传递指针到指针:

这是使用类型映射的另一种方法。它针对的是 Perl,而不是 Java,但概念是相同的。我终于设法使用类型映射而不使用辅助函数来让它工作:

对于此功能:

typedef void *    MyType;
int getblock( int a, int b, MyType *block );

我有 2 个类型图:

%typemap(perl5, in, numinputs=0) void ** data( void * scrap )
{
    $1 = &scrap;
}

%typemap(perl5, argout) void ** data
{
    SV* tempsv = sv_newmortal();
    if ( argvi >= items ) EXTEND(sp,1);
    SWIG_MakePtr( tempsv, (void *)*$1, $descriptor(void *), 0);
    $result = tempsv;
    argvi++;
}

函数定义为:

int getblock( int a, int b, void ** data ); 

在我的 swig .i 文件中。现在,这会在 argout 类型映射中传回一个不透明的指针,因为这对这种特殊情况很有用,但是,如果您愿意,您可以将 SWIG_MakePtr 行替换为实际处理指针中的数据的内容。此外,当我想将指针传递给函数时,我有一个如下所示的类型映射:

%typemap(perl5, in) void * data
{
    if ( !(SvROK($input)) croak( "Not a reference...\n" );

    if ( SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0 ) == -1 )
        croak( "Couldn't convert $1 to $1_descriptor\n");
}

函数定义为:

int useblock( void * data );

在我的 swig .i 文件中。

显然,这都是 perl,但就类型映射架构而言,应该直接映射到 Java。希望能帮助到你...

于 2013-03-06T17:26:02.097 回答