如何使用JNA将Java基本数组传递给C dll?

问题描述

使用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中,我有rowLowerrowUpperrowStartscolumnscolumnselements作为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);