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

标签 java swig

如何配置 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/

相关文章:

java - 汉字编码成太多字节

Java Cplex 两个决策变量的乘积

python - 在 SWIG 中获取从 C++ 到 Python 的 char* 输出

c++ - 缺少分号 : C++ or SWIG issue?

python - 如何查看 SWIG 接口(interface)、TensorFlow 背后的 C++ 函数调用

java - 运行 ADF Morena 应用程序时出错?

java - 在 Java 中调用该类的任何方法之前调用方法

c++ - 如何在 Python 中实现 C++ 类,由 C++ 调用?

java - Spring Security中的多重身份验证管理器

c# - 通过 SWIG 为 C# 编译 Quantlib