使用SWIG将C++ char*转换为Java中的char[]而不是String

5

我正在尝试使用Java包装以下C++函数:

char* MyClass::to_cstring();

该函数的输出以Java字符串对象的形式返回。我希望其返回一个char[] Java数组。目前,我正在使用"typemaps.i"和"std_string.i"。是否有一种方法可以重写该行为,使std::string仍然作为Java String返回,但char*则作为Java char数组返回?
如果使用Java byte[]而不是char[],那么就不需要担心在8位C ++字符和Java的16位Unicode之间进行转换了,怎么样?

至少在Java中,那将是一个byte[]。Java的char是UTF-16代码单元。 - Sebastian Redl
1个回答

3
为此,您需要用自己的类型映射替换默认的SWIG提供的类型映射。最简单的方法只需要编写一些Java“粘合剂”即可:
%module test

%typemap(jstype) char *to_cstring() "byte[]";
%typemap(javaout) char *to_cstring() {
  return $jnicall.getBytes();
}

%inline %{
char *to_cstring() {
  static char ret[] = "hello world";
  return ret;
}
%}

通过在默认返回的字符串上调用getBytes(),可以完全按照您的要求执行操作。

您也可以使用自己的JNI来将其作为字节数组返回到从本地代码中进行操作:

%module test

%typemap(jstype) char *to_cstring() "byte[]";
%typemap(jtype) char *to_cstring() "byte[]";
%typemap(javaout) char *to_cstring() {
  return $jnicall;
}
%typemap(jni) char *to_cstring() "jbyteArray";
%typemap(out) char *to_cstring() {
  const size_t len = strlen($1);
  $result = JCALL1(NewByteArray, jenv, len);
  // TODO: check that this succeeded
  JCALL4(SetByteArrayRegion, jenv, $result, 0, len, (const jbyte*)$1);
}

%inline %{
char *to_cstring() {
  static char ret[] = "hello world";
  return ret;
}
%}

这里的区别在于将映射到byte[]的操作发生在生成的JNI中,而不是Java粘合剂中。现在,粘合剂直接代理到未更改的JNI。

我能够使用以下Java进行测试和验证这些类型映射:

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    byte[] ret = test.to_cstring();
    System.out.println(ret.length);
    System.out.println((char)ret[0]);
  }
}

在这两个示例中,类型映射匹配返回类型(char *)和函数to_cstring()。您可以调整此类型映射匹配的选择性。它目前不会改变大多数常规用法,您还可以使用%apply将类型映射复制到其他不完全匹配的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接