问题涉及对 C 函数 (API) 的 JAVA 调用,该函数返回一个指向指针的指针作为 argout 参数。我试图从 JAVA 调用 C API,但我无法修改 API。
2 回答
[Swig] Java:使用 C 辅助函数传递指针到指针
- 问题涉及对 C 函数 (API) 的 JAVA 调用,该函数返回一个指向指针的指针作为 argout 参数。我试图从 JAVA 调用 C API,但我无法修改 API。
API.h 头文件包含:
extern int ReadMessage(HEADER **hdr);
原始的 C 调用如下所示:
HEADER *hdr;
int status;
status = ReadMessage(&hdr);
API 的功能是将数据存储在指针指定的内存位置。
- 我尝试使用 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。
- 我终于放弃了将指针作为输入参数传递。相反,我在 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;
}%}
- 上面的内联函数可能会泄漏内存,因为 Java 不会获得 ReadMessageHelper 创建的内存的所有权,因为 HEADER 实例是在堆上创建的。
内存泄漏的修复方法是将 ReadMessageHelper 定义为一个新对象,以便 Java 控制内存。
%newobject ReadMessageHelper();
JAVA 调用现在看起来像:
HEADER hdr;
hdr = SWIG.ReadMessageHelper();
如果你像我一样幸运的话,你可能有另一个 API 可用于释放消息缓冲区。在这种情况下,您不必执行上一步。
SWIG 大师威廉·富尔顿 (William Fulton) 对上述方法有这样的看法:
“我不认为辅助函数是一个杂物,更像是解决棘手问题的最简单解决方案。考虑 ReadMessage() 的等效纯 100% Java 代码。我不认为 Java 类是通过引用传递的等价物,并且不存在对引用的引用或指向 Java 中指针的指针之类的东西。在您拥有的 C 函数中,一个 HEADER 实例由 ReadMessage 创建并传递回调用者。如果不提供一些围绕 HEADER 的包装类并将包装器传递给 ReadMessage 函数,我看不出如何在 Java 中做同样的事情。归根结底,ReadMessage 返回一个新创建的 HEADER,而 Java 返回新创建对象的方式是在返回值中返回它,而不是通过参数。”</p>
使用 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。希望能帮助到你...