5

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

char* MyClass::to_cstring();

此函数的此输出作为 Java String 对象返回。我希望它作为char[]Java 数组返回。我目前正在使用“typemaps.i”和“std_string.i”。有没有办法覆盖 std::string 仍然作为 Java 返回的行为String,但char*作为 Java char 数组返回?

使用 Javabyte[]而不是char[]这样就不必担心在 8 位 C++ 字符和 Java 的 16 位 Unicode 之间进行转换如何?

4

1 回答 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()通过在默认返回的幕后调用,完全符合您的要求String

您也可以使用自己的一些 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将类型映射复制到其他不完全匹配的情况。

于 2013-07-14T11:12:45.763 回答