使用 Swig 在 C 和 java 之间传递数组
Passing arrays between C and java with Swig
我精通 C,但不精通 Java,我正在尝试使用 Swig 从 Java 调用 C。简单调用工作正常,但我无法使用 carrays.i
或 arrays_java.i
方法交换数组。两者都没有任何完整的例子。
AMItest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%include "AMItest.h"
AMItest.h:
extern int AMItest(double *Array, int Start, int End);
AMItest.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include "AMItest.h"
int AMItest(double *Array, int Start, int End) {
if (End<=Start) {
fprintf(stderr, "Start must be lower than End\n");
return EDOM;
}
for (int i=0; i<=End-Start; i++)
Array[i]=sin(i/4.);
return 0;
}
main.java:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
double[] myArray = new double[11];
System.out.println(AMItest.AMItest(myArray, 10, 20));
for (int i=0; i<myArray.length; i++)
System.out.print(myArray[i] + " ");
}
}
编译:
$ rm -f AMItest AMItest*.java SWIG*.java *.class *.o *.a *.so *_wrap.c
$ swig -java AMItest.i
$ gcc -fPIC -c AMItest.c AMItest_wrap.c -I/usr/lib/jvm/java-11-openjdk-amd64/include -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux
$ gcc -shared AMItest.o AMItest_wrap.o -W -o libAMItest_swig.so
$ javac main.java
main.java:7: error: incompatible types: double[] cannot be converted to SWIGTYPE_p_double
System.out.println(AMItest.AMItest(myArray, 10, 20));
谷歌搜索 SWIGTYPE_p_* errors
导致的(无用的)链接少得惊人。我也尝试过使用 arrays_java.i
或将其添加到 .i 文件中:
%array_functions( double, double )
%include <typemaps.i>
%apply (double *OUTPUT, int, int) {(double *Array, int Start, int End)};
这是我的 .i 文件还是我的 Java 的问题?!?
像这样调整你的AMItest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "arrays_java.i"
%apply double[] {double *};
%include "AMItest.h"
Sometimes a C function expects an array to be passed as a pointer...
One of the ways to wrap this is to apply the Java array typemaps that come in the arrays_java.i library file ... The ANY size will ensure the typemap is applied to arrays of all sizes. You could narrow the typemap matching rules by specifying a particular array size. Now you can use a pure Java array and pass it to the C code.
在此处查看文档:http://www.swig.org/Doc4.0/SWIGDocumentation.html#Java_unbounded_c_arrays
测试
如上所示使用您提供的带有修改后的 AMItest.i 的示例,调用 java main
时您将获得以下输出:
0
0.0 0.24740395925452294 0.479425538604203 0.6816387600233342 0.8414709848078965 0.9489846193555862 0.9974949866040544 0.9839859468739369 0.9092974268256817 0.7780731968879213 0.5984721441039564
大型阵列的更高效替代方案
对于包含 11 个双精度元素的数组,您可能希望使用上面显示的方法。但我不想隐藏 SWIG 文档中显示的替代方法:
This approach is probably the most natural way to use arrays. However, it suffers from performance problems when using large arrays as a lot of copying of the elements occurs in transferring the array from the Java world to the C++ world. An alternative approach to using Java arrays for C arrays is to use an alternative SWIG library file carrays.i. This approach can be more efficient for large arrays as the array is accessed one element at a time.
您的示例需要在两个地方进行修改,如下所示:
AKITest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%array_functions(double, doubleArray);
%include "AMItest.h"
你稍作修改后的 main.java 将如下所示:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
int size = 11;
SWIGTYPE_p_double myArray = AMItest.new_doubleArray(size);
AMItest.AMItest(myArray, 10, 20);
for (int i=0; i<size; i++)
System.out.print(AMItest.doubleArray_getitem(myArray, i) + " ");
}
}
结果是一样的。
我精通 C,但不精通 Java,我正在尝试使用 Swig 从 Java 调用 C。简单调用工作正常,但我无法使用 carrays.i
或 arrays_java.i
方法交换数组。两者都没有任何完整的例子。
AMItest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%include "AMItest.h"
AMItest.h:
extern int AMItest(double *Array, int Start, int End);
AMItest.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include "AMItest.h"
int AMItest(double *Array, int Start, int End) {
if (End<=Start) {
fprintf(stderr, "Start must be lower than End\n");
return EDOM;
}
for (int i=0; i<=End-Start; i++)
Array[i]=sin(i/4.);
return 0;
}
main.java:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
double[] myArray = new double[11];
System.out.println(AMItest.AMItest(myArray, 10, 20));
for (int i=0; i<myArray.length; i++)
System.out.print(myArray[i] + " ");
}
}
编译:
$ rm -f AMItest AMItest*.java SWIG*.java *.class *.o *.a *.so *_wrap.c
$ swig -java AMItest.i
$ gcc -fPIC -c AMItest.c AMItest_wrap.c -I/usr/lib/jvm/java-11-openjdk-amd64/include -I/usr/lib/jvm/java-11-openjdk-amd64/include/linux
$ gcc -shared AMItest.o AMItest_wrap.o -W -o libAMItest_swig.so
$ javac main.java
main.java:7: error: incompatible types: double[] cannot be converted to SWIGTYPE_p_double
System.out.println(AMItest.AMItest(myArray, 10, 20));
谷歌搜索 SWIGTYPE_p_* errors
导致的(无用的)链接少得惊人。我也尝试过使用 arrays_java.i
或将其添加到 .i 文件中:
%array_functions( double, double )
%include <typemaps.i>
%apply (double *OUTPUT, int, int) {(double *Array, int Start, int End)};
这是我的 .i 文件还是我的 Java 的问题?!?
像这样调整你的AMItest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "arrays_java.i"
%apply double[] {double *};
%include "AMItest.h"
Sometimes a C function expects an array to be passed as a pointer... One of the ways to wrap this is to apply the Java array typemaps that come in the arrays_java.i library file ... The ANY size will ensure the typemap is applied to arrays of all sizes. You could narrow the typemap matching rules by specifying a particular array size. Now you can use a pure Java array and pass it to the C code.
在此处查看文档:http://www.swig.org/Doc4.0/SWIGDocumentation.html#Java_unbounded_c_arrays
测试
如上所示使用您提供的带有修改后的 AMItest.i 的示例,调用 java main
时您将获得以下输出:
0
0.0 0.24740395925452294 0.479425538604203 0.6816387600233342 0.8414709848078965 0.9489846193555862 0.9974949866040544 0.9839859468739369 0.9092974268256817 0.7780731968879213 0.5984721441039564
大型阵列的更高效替代方案
对于包含 11 个双精度元素的数组,您可能希望使用上面显示的方法。但我不想隐藏 SWIG 文档中显示的替代方法:
This approach is probably the most natural way to use arrays. However, it suffers from performance problems when using large arrays as a lot of copying of the elements occurs in transferring the array from the Java world to the C++ world. An alternative approach to using Java arrays for C arrays is to use an alternative SWIG library file carrays.i. This approach can be more efficient for large arrays as the array is accessed one element at a time.
您的示例需要在两个地方进行修改,如下所示:
AKITest.i:
%module AMItest
%{
#include "AMItest.h"
%}
%include "carrays.i"
%array_functions(double, doubleArray);
%include "AMItest.h"
你稍作修改后的 main.java 将如下所示:
public class main {
public static void main(String argv[]) {
System.loadLibrary("AMItest_swig"); // File is libAMItest_swig.so
int size = 11;
SWIGTYPE_p_double myArray = AMItest.new_doubleArray(size);
AMItest.AMItest(myArray, 10, 20);
for (int i=0; i<size; i++)
System.out.print(AMItest.doubleArray_getitem(myArray, i) + " ");
}
}
结果是一样的。