Java 使用SWIG与阵列交互的正确方法
我对swig中的类型映射以及如何使用数组有点迷茫。我已经准备了一个使用swig在java和c之间使用数组的工作示例,但我不知道这是否是正确的方法 基本上,我想把一个字节数组Java 使用SWIG与阵列交互的正确方法,java,c,swig,Java,C,Swig,我对swig中的类型映射以及如何使用数组有点迷茫。我已经准备了一个使用swig在java和c之间使用数组的工作示例,但我不知道这是否是正确的方法 基本上,我想把一个字节数组byte[]作为一个“有符号字符*”+从java传递到c,在c中修改它,查看java中的变化,在c中创建一个数组,并在java中使用它 我已经看了这些问题: , , 事实上,我们是以这些解决方案为指导来做例子的 这是我在arrays.h文件中的代码: #include <iostream> bool cre
byte[]
作为一个“有符号字符*”+从java传递到c,在c中修改它,查看java中的变化,在c中创建一个数组,并在java中使用它
我已经看了这些问题:
,
,
事实上,我们是以这些解决方案为指导来做例子的
这是我在arrays.h文件中的代码:
#include <iostream>
bool createArray(signed char ** arrCA, int * lCA){
*lCA = 10;
*arrCA = (signed char*) calloc(*lCA, sizeof(signed char));
for(int i = 0; i < *lCA; i++){
(*arrCA)[i] = i;
}
return *arrCA != NULL;
}
bool readArray(const signed char arrRA[], const int lRA){
for(int i = 0; i < lRA; i++){
std::cout << ((unsigned int) arrRA[i]) << " ";
}
std::cout << std::endl;
return true;
}
bool modifyArrayValues(signed char arrMA[], const int lMA){
for(int i = 0; i < lMA; i++){
arrMA[i] = arrMA[i] * 2;
}
return true;
}
bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){
*lMALOut = 5;
*arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));
for(int i = 0; i < *lMALOut; i++){
(*arrMALOut)[i] = arrMALIn[i];
}
return true;
}
最后是测试它的Java代码:
public class Run{
static {
System.loadLibrary("Arrays");
}
public static void main(String[] args){
byte[] test = arrays.createArray();
printArray(test);
arrays.readArray(test);
arrays.modifyArrayValues(test);
printArray(test);
byte[] test2 = arrays.modifyArrayLength(test);
printArray(test2);
}
private static void printArray(byte[] arr){
System.out.println("Array ref: " + arr);
if(arr != null){
System.out.println("Array length: " + arr.length);
System.out.print("Arrays items: ");
for(int i =0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
System.out.println();
}
}
是C++中的原BUTF使用STD::String来存储数据,但是这个数据是二进制的,所以它不能被返回作为一个普通的java字符串,因为它被截断,更多的是在.< /P>中。 因此,我的想法是为序列化的Protobuf返回Java a
byte[]
(就像Java版本的协议缓冲区一样),并接受byte[]
来解析Protobuf。为了避免在导出的第二个参数中获取SWIGTYPE_p_std_string
,并在导入的第二个参数中使用string,y使用%extend包装了这两个函数,如下所示:
class SomeLibrary {
bool export(const std::string & sName, std::string & toExport);
bool import(const std::string & sName, const std::string & toImport);
}
%extend SomeLibrary{
bool export(const std::string & sName, char ** toExportData, int * toExportLength);
bool import(const std::string & sName, char * toImportData, int toImportLength);
}
现在我应该可以制作打印图了
但是为了更通用,我要求提供从Java到SWIG的数组操作的通用性,使用本机Java
字节[]
不要打折carrays。我会自动执行。也就是说,SWIG已经有了一些方便的类型图:
%module test
%apply(char *STRING, size_t LENGTH) { (char *str, size_t len) };
%inline %{
void some_func(char *str, size_t len) {
}
%}
它在Java接口中生成一个函数:
public static void some_func(byte[] str)
i、 它需要一个数组,你可以像普通的一样用Java构建,并为你填充指针和长度。几乎是免费的
目前的代码几乎肯定会泄漏—您希望在argout typemap中调用free()
,以释放分配的内存,一旦它被复制到新的Java数组中
您可以根据参数的类型和名称有选择地应用类型映射。您还可以请求显式地使用类型映射,否则它将不会与%apply
一起使用,如我上面展示的示例所示。(实际上,它复制了类型映射,因此,如果您只修改了其中一个,则在一般情况下不会替换它)
一般来说,将数组从java传递到C++或使用已知大小数组的类型映射比C++从java返回Java更简单,因为大小信息更加明显。
我的建议是,计划在Java内部进行大量的分配—分配和设计您的函数,这些函数可能会使数组以两种模式运行:一种表示所需的大小,另一种实际执行工作。您可以通过以下方式实现:
ssize_t some_function(char *in, size_t in_sz) {
if (in_sz < the_size_I_need) {
return the_size_I_need; // query the size is pretty fast
}
// do some work on in if it's big enough
// use negative sizes or exceptions to indicate errors
return the_size_I_really_used; // send the real size back to Java
}
请注意,对于默认类型映射,需要
新字节[0]
,因为它们不允许将null
用作数组-如果需要,可以添加允许此操作的类型映射,或者使用%extend
提供不需要空数组的重载。这里有详细说明:
下面的接口文件将生成java中的byte[]方法:
%apply (char *STRING, size_t LENGTH) { (const char data[], size_t len) }
%inline %{
void binaryChar1(const char data[], size_t len) {
printf("len: %d data: ", len);
for (size_t i=0; i<len; ++i)
printf("%x ", data[i]);
printf("\n");
}
%}
%apply(字符*字符串,大小\长度){(常量字符数据[],大小\长度)}
%内联%{
void binaryChar1(常量字符数据[],大小长度){
printf(“len:%d数据:”,len);
对于(sisixt i=0;II认为你正在使它比它需要的复杂):我想你想在java中建立一个大数组然后把它传递到C++函数中吗?我可以显示一个简单的解决方案,并且在路上也希望解决一些其他问题。例如,你想通过<代码>字节[]
转换为类似于void foo(const char*arr,size\t len)的函数
?@Flexo-我也认为我做的太复杂了。我也编辑了这个问题,提供了更多的上下文。要回答更多的几点:SetByteArrayRegion
复制数据。Java数组将由通常的Java机制管理。它是在JNI调用本地创建的,并将在对它的ast引用被删除。我已经测试了这个解决方案,对输入值非常有效。对于输出,我无法事先知道所需的大小,我的意思是它正在序列化一个protobuf,所以我只知道序列化时需要多少空间,我不想丢弃序列化的数据,因为它不适合我传递的数组,我是一个lso不希望返回到Java的数组比包含的数据大,因为现有代码在没有更改的情况下无法工作(这可以通过在Java端复制数组来避免).我已经更改了输入到解决方案的类型图,以及原始的输出typemaps@JavierMr这也是有道理的——我会使用类似于这个答案的输入(或组合输入/输出,因为类型映射会将值复制回来)以及创建新数组。非常感谢您对我所做的关于swig的所有问题的帮助。@flex,当我根据您的示例构建%module测试时,生成的java输出代码是public static void some_func(String str)
。输入参数是String,而不是byte[].No,%inline
不会产生不同的效果,它相当于写两次,一次在%{%}
内部,一次不在内部。如果不起作用,可能您有不同的顺序或不同的变量名,因此%apply
无法正确应用gtet
int sz = module.some_function(new byte[0]);
byte result[] = new byte[sz];
sz = module.some_function(result);
%apply (char *STRING, size_t LENGTH) { (const char data[], size_t len) }
%inline %{
void binaryChar1(const char data[], size_t len) {
printf("len: %d data: ", len);
for (size_t i=0; i<len; ++i)
printf("%x ", data[i]);
printf("\n");
}
%}