gpt4 book ai didi

java - 在 Java 中处理 FILE * C 输入参数的 SWIG 配置

转载 作者:行者123 更新时间:2023-11-30 04:56:41 24 4
gpt4 key购买 nike

如何配置 SWIG .i 文件来处理 C FILE * 类型?下面的函数设置一个文件,以便可以将日志输出写入其中。我需要从 Java 类中调用 if 。目前,当我仅将 C 头文件包含在以下函数中时,SWIG 会生成 public static void setLogFile(SWIGTYPE_p_FILE fd) 函数。有任何想法吗?

C 函数:

void setLogFile(FILE *fd);

我尝试使用下面的#1 并得到以下异常:

测试.i:

%module Example
%{
#include "headerLogFile.h"
%}

%inline %{
void setLogFile(const char *fn) {
FILE *f = fopen(fn, "w");
setLogFile(f);
}
%}
%ignore setLogFile;
%include "headerLogFile.h"

异常(exception):

[exec] test_wrap.c:193: error: conflicting types for 'setLogFile'
[exec] /test/include/headerLogFile.h:96: error: previous declaration of 'setLogFile' was here
[exec] test_wrap.c: In function `setLogFile':
[exec] test_wrap.c:195: warning: passing arg 1 of `setLogFile' from incompatible pointer type

最佳答案

给出的 test.h 看起来像:

#include <stdio.h>

inline void setLogFile(FILE *fd) {
fprintf(fd, "Test\n");
fflush(fd);
}

我可以看到您可能选择采用三种方法来包装此函数:

方法 1 - 从 Java 传递 String:

向 Java 公开一个函数,该函数需要以 String 形式传递文件名,而不是 FILE*:

%module method1

%{
#include "test.h"
%}

%inline %{
void setLogFile(const char *fn) {
FILE *f = fopen(fn, "w");
setLogFile(f);
}
%}

这使用 %inline 指示 SWIG 在定义该函数的同时包装该函数。如果您仍然使用 %include "test.h" 那么您可能会想要 hide the original version from SWIG .

<小时/>

方法 2 - 包装更多 stdio.h:

不仅仅封装 setLogFile,还可以根据需要封装 fopenfmemopen 等内容。 (我个人不太喜欢这个解决方案,所以我没有为此做一个例子)

<小时/>

方法 3 - 公开一个采用 FileOutputStream 的 Java 接口(interface):

%module method3

%{
#include "test.h"
#include <cassert>
%}

// 3:
%typemap(jni) FILE *fd "jobject"
// 1:
%typemap(jstype) FILE *fd "java.io.FileOutputStream"
// 2:
%typemap(jtype) FILE *fd "java.io.FileDescriptor"
// 4:
%typemap(in) (FILE *fd) {
jfieldID field_fd;
jclass class_fdesc;
int rawfd;
class_fdesc = jenv->FindClass("java/io/FileDescriptor");
assert(class_fdesc);
field_fd = jenv->GetFieldID(class_fdesc, "fd", "I");
assert(field_fd);
rawfd = jenv->GetIntField($input, field_fd);
$1 = fdopen(rawfd, "w");
// Add some code to throw a Java exception if $1 is NULL (i.e. error)
}
// 5:
%typemap(javain, pre=" retainFD = $javainput;",
throws="java.io.IOException") FILE *fd "$javainput.getFD()"
// 6:
%pragma(java) modulecode=%{
private static java.io.FileOutputStream retainFD;
%}

%include "test.h"

这会执行以下操作:

  1. 我们希望模块实际公共(public)部分的输入为 java.io.FileOutputStream
  2. JNI 代码的 Java 端将采用 java.io.FileDescriptor 来代替。
  3. JNI 代码的 C++ 端会将其视为作业对象
  4. 在 C++ 方面,我们要做一些有点邪恶的事情 - 读取 FileDescriptor 类中的私有(private) int 字段 ( see here )。这可能是不可移植的,并且读取类的私有(private)部分通常被认为是不好的,但它允许我们获取可以传递给 fdopen() 的东西,以获取 FILE* “真正的”电话
  5. 大多数情况下,此类型映射采用 FileOutputStream 并对其调用 getFD() 以获取其 FileDescriptor 对象。它还添加了一个异常规范来匹配 getFD() 并执行另一个函数,该函数是下一点的一部分
  6. 我们需要确保 Java 不会进行垃圾收集并最终确定 FileOutputStream,这会关闭文件句柄并使我们的 FILE* 无效。我们通过在 private static 变量中保留对 FileOutputStream 的引用来实现此目的。前一个类型映射的 pre="... 会导致保留最新的类型映射,直到我们更改为另一个类型映射。(如果我们确实调用 setLogFile 两次就可以了,事实上,我们发布了对之前 FileOutputStream 的引用,这很好)

关于java - 在 Java 中处理 FILE * C 输入参数的 SWIG 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8320605/

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