3

JNA を使用して Java コードを DLL にマッピングする場合、C の関数引数がポインタの場合、C 呼び出しでJava 配列 ( int[]、 )をどのように渡す/使用する必要がありますか? double[]私はバグに直面しています.Cへの配列のマッピングのどこかにあると思います.


私が試したこと:そして私が修正しようとしているバグ

私のプロジェクトでは、clp-javaの背後にあるコードベースを再構築する必要があります。そうすることで、LP 問題の制約を追加する次の関数を含む C ヘッダー ファイルがあります (例: 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およびrowUpperJavarowStarts配列(のいずれか) がありcolumnscolumnsます。clp -javaは BridJ を使用し、上記の関数は経由で呼び出されますelementsint[]double[]

CLPNative.clpAddRows(pointerToModel, number, 
        Pointer.pointerToDoubles(rowLower), 
        Pointer.pointerToDoubles(rowUpper), 
        Pointer.pointerToInts(rowStarts), 
        Pointer.pointerToInts(columnscolumns), 
        Pointer.pointerToDoubles(elements));

プレーンな JNA を使用すると、JNA のドキュメントには、C 関数の呼び出しが次のようになるように、配列がポインターにマップされると記載されています。

CLPNative.clpAddRows(pointerToModel, number, 
        rowLower, rowUpper, rowStarts, columnscolumns, elements);

残念ながら、両方のメソッドに同じ配列を渡してメモリ内のデータを取得すると、制約の2 番目の変数に対して異なる答えが得られます (最初の変数は問題ありません)。BridJ は -3.3 を生成し、私の JNA メソッドは 1.777E-307 を出力します。同じ DLL、同じマシン (Java 11)。

インターネットでこの例を見つけました。これは、Java の配列を JNA ポインターにマップし、このポインターを C 関数に渡します。これを使ってみました:

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;
  }

JNA関数呼び出しでこれを使用すると(そしてそれに応じてJNAインターフェースを変更すると)、「無効なメモリアクセス」というJavaエラーが発生します。この StackOverflow Q/Aに基づいてこれを修正します(のオフセットsetInt()を でシフトする必要がありますNative.getNativeSize(Integer.TYPE)。同じ誤った出力が明らかになります (x2 の係数は -3.3 ではなく 1.777E-307 です)。

CLPNative.clpAddRows(pointerToModel, number, 
        doubleArrayToPointer(rowLower),....);

追加情報:次の関数/メソッドで係数を確認します。

  public double getNativeConstraintCoefficient(CLPConstraint pConstraint, CLPVariable pVariable) {
    <... some magic to compute the position...>
     Pounter<Double> elements = CLPNative.Clp_GetElements(pointerToModel);
     return elements.getDoubleAtIndex(pos-1); // using BridJ
     return elements.getDouble(pos - 1)  // using JNA
}
4

2 に答える 2