Swig:将返回类型std :: string(二进制)转换为java byte

我的情况是我有一个C ++类(MyClass),其方法具有以下签名:

bool getSerialized(const stdString & name, std::string & serialized); 

其中name是参数,序列化是out参数。

我通过在’i’文件中创建%extend和%ignore声明来实现它,如下所示:

 %extend MyClass{ std::string getSerialized(const std::string & name){ std::string res; $self->getSerialized(name, res); return res; }; %rename("$ignore", fullname=1) "MyClass::getSerialized"; 

所以这个方法可以在Java中使用:

 MyClass mc = new MyClass(); String res = mc.getSerialized("test"); 

但是现在我遇到了一个问题,序列化的std :: string包含二进制数据,包括’\ 0’字符表示C String的结尾,实际上下面的代码显示了C ++中的问题:

 std::string s; s.push_back('H'); s.push_back('o'); s.push_back(0); s.push_back('l'); s.push_back('a'); std::cout << "Length of std::string " << s.size() << std::endl; std::cout << "CString: '" << s.c_str() << "'" << std::endl; 

上面的代码显示:

 Length of std::string 5 CString: 'Ho' 

正如我在SWIG生成的包装文件中看到的那样,wrap方法实际上调用了c_str(),包的代码:

 jstring jresult = 0 ; std::string result; result = (arg1)->getSerialized(); jresult = jenv->NewStringUTF((&result)->**c_str()**); return jresult; 

正如预期的那样,Java中收到的String被截断了。 那么我怎么能改变(大概)我的%扩展函数包装器,所以我可以将它作为字节数组(byte [])返回,而不需要事先知道数组的长度。 如果可以在SWIG层中创建byteArray会很棒,所以我可以从Java调用方法,如:

 byte[] serialized = mc.getSerialized("test"); 

其他注意事项:给出了使用std :: string存储二进制数据的方法,以及使用Google protobuf库C ++ protobuf用法的返回类型

有一个非常类似的问题,包括tittle Swig:将返回类型std :: string转换为java byte [],但二进制数据没有任何情况,因此这里给出的解决方案不适用。

使用SWIG 2。

您可以使用一些类型映射和一些JNI来执行您要执行的操作。 我把一个例子放在一起:

 %module test %include  %typemap(jtype) bool foo "byte[]" %typemap(jstype) bool foo "byte[]" %typemap(jni) bool foo "jbyteArray" %typemap(javaout) bool foo { return $jnicall; } %typemap(in, numinputs=0) std::string& out (std::string temp) "$1=&temp;" %typemap(argout) std::string& out { $result = JCALL1(NewByteArray, jenv, $1->size()); JCALL4(SetByteArrayRegion, jenv, $result, 0, $1->size(), (const jbyte*)$1->c_str()); } // Optional: return NULL if the function returned false %typemap(out) bool foo { if (!$1) { return NULL; } } %inline %{ struct Bar { bool foo(std::string& out) { std::string s; s.push_back('H'); s.push_back('o'); s.push_back(0); s.push_back('l'); s.push_back('a'); out = s; return true; } }; %} 

它声明C ++包装器为与bool foo匹配的函数返回一个Java字节数组。 它还设置了一个临时的std::string来实现foo的实际实现,它隐藏了Java接口本身的输入参数。

一旦调用完成,它就会创建并返回一个字节数组,前提是该函数没有返回false。

我检查了它是否按预期工作:

 public class run { public static void main(String[] argv) { String s = "ho\0la"; System.out.println(s.getBytes().length); System.loadLibrary("test"); Bar b = new Bar(); byte[] bytes = b.foo(); s = new String(bytes); System.out.println(s + " - " + s.length()); assert(s.charAt(2) == 0); } } 

您应该从c_str()的返回类型中const jbyte*const jbyte*的影响 – 它可能并不总是您想要的。

作为替代方案,如果输出字节数组的大小实际上是固定的或平凡可预测的,那么您可以将其作为输入开始预先分配。 这可以工作,因为数组首先通过引用有效地传递给函数。