问题描述
使用JNA将Java代码映射到DLL时,当C的函数参数是指针时,如何在C调用中传递/使用Java数组(int[]
,double[]
)?我面临一个错误,我认为它是在数组到C的映射中的某个位置。
我尝试过的事情:以及我要修复的错误
对于我的项目,我需要重组clp-java之后的代码库。为此,我有一个带有以下功能的C头文件,该文件添加了LP问题的约束(例如:2.25*x1 - 3.3*x2 =4
)。
CLPLIB_EXPORT void CLP_LINKAGE Clp_addRows(Clp_Simplex *model,int number,const double *rowLower,const double *rowUpper,const CoinBigIndex *rowStarts,const int *columns,const double *elements);
在Java中,我有rowLower
,rowUpper
,rowStarts
,columnscolumns
和elements
作为Java数组({{1的int[]
}}。 clp-java使用BridJ,上面的函数通过
double[]
JNA documentation使用普通的JNA,指出数组映射到指针,这样对C函数的调用将是:
CLPNative.clpAddRows(pointerToModel,number,Pointer.pointerTodoubles(rowLower),Pointer.pointerTodoubles(rowUpper),Pointer.pointerToInts(rowStarts),Pointer.pointerToInts(columnscolumns),Pointer.pointerTodoubles(elements));
不幸的是,当我将相同的数组传递给两个方法并检索内存中的数据时,对于约束中的第二个变量,我得到了不同的答案(第一个可以):BridJ产生-3.3 ,我的JNA方法输出1.777E-307。相同的DLL,相同的机器(Java 11)。
在互联网上,我发现了this example,它将Java中的数组映射到JNA指针,并将该指针传递给C函数。这是我尝试使用的:
CLPNative.clpAddRows(pointerToModel,rowLower,rowUpper,rowStarts,columnscolumns,elements);
尽管如果我在JNA函数调用中使用它(并相应地更改JNA接口),则会收到Java错误“无效的内存访问”。根据{{3}}修复此问题(private Pointer intArrayToPointer(int[] pArray) {
Pointer pointerToArray = new Memory(pArray.length*Native.getNativeSize(Integer.TYPE));
for (int i=0; i< pArray.length; i++) {
pointerToArray.setInt(i,pArray[i]);
}
return pointerToArray;
}
中的偏移量需要偏移setInt()
,显示相同的错误输出(x2的系数为1.777E-307而不是-3.3)>
Native.getNativeSize(Integer.TYPE)
CLPNative.clpAddRows(pointerToModel,doubleArrayToPointer(rowLower),....);
解决方法
找到它,这是我读取数据的方式,而不是我写数据的方式。
BridJ是一个精美的包装器,它确保您在对应于double的索引处读取指针(在我的机器上是8位)。换句话说:index = 0读取1-8位,index = 2读取9-16位。
JNA并不“那么花哨”。 Pointer.getDouble(offset)从其指向的地址开始读取一个double(8位值)。 offset = 0读取1-8位,offset = 1读取2-9。为避免这种情况,需要将偏移量乘以您要查找的数据类型
Pointer.getDouble(offset*Native.getNativeSize(Double.TYPE))
,
在your answer中,您注意到BridJ索引与数组相对应,因此每个索引都是一个新的ConstraintLayout(modifier = modifier.fillMaxSize()) {
val (button1,button2) = createRefs()
Button(
onClick = {},modifier = Modifier.constrainAs(button1) {
top.linkTo(parent.top,margin = 16.dp)
}
) {
Text(text = "Button 1")
}
Button(
onClick = {},modifier = Modifier.constrainAs(button2) {
top.linkTo(button1.bottom,margin = 4.dp)
linkTo(button1.end,parent.end,startMargin = 20.dp,endMargin = 20.dp,bias = 0F)
width = Dimension.preferredWrapContent
}
) {
Text(text = "Button 2")
}
}
,并正确地指出,如果您仅获取单个double
在JNA指针中,您需要使用 byte 偏移量,表明它“不那么花哨”。
但是,如果您愿意,JNA可以只是“花哨”。只需使用此:
double
例如:
Pointer.getDoubleArray(offset,arraySize);