2017-02-04 22 views
6

Próbuję wywołać krótki ** w C z JNA.JNA dwuwymiarowe tablice

C wygląda następująco:

void compute(short** in, int row, int col) { 
    for (int i = 0; i < row; i++) { 
     for (int j = 0; j < col; j++) { 
      printf("in[%d][%d] = %d\n", i,j, in[i][j]); 
     } 
    } 
} 
  • Przechodząc krótki [] [] z JNA nie działa.

  • Dokumentacja JNA mówi "Aby odwzorować natywną tablicę wielowymiarową, użyj jednowymiarowej tablicy Javy", ale to nie działa. Podczas wywoływania "nativeLib.compute" (nowy skrót [] {1, 2, 3, 4}, 2, 2): nativeLib.compute (new short [] {1, 2, 3, 4}); uzyskać: java.lang.Error: nieprawidłowy dostęp do pamięci w com.sun.jna.Native.invokeVoid (metoda podstawowa)

  • Wydaje się, że PointerByReference jest potrzebne, próbowałem wypełnić PointerByReference z PointerByReference zawierającej krótkie wartości, ale to nie działa:

    Pointer pointerOfArray = new Memory(row * col * Native.getNativeSize(Short.TYPE)); 
    for(int i=0;i<row;i++) { 
    
        Pointer pointer = new Memory(col * Native.getNativeSize(Short.TYPE)); 
        for(int j=0;j<col;j++) { 
         pointer.setShort(j*Native.getNativeSize(Short.TYPE), in[i][j]); 
        } 
        pointerOfArray.setPointer(i*row*Native.getNativeSize(Short.TYPE), pointer); 
    } 
    
  • próbowałem również:

    Pointer pointer = new Memory(4*Short.SIZE); 
    
    Pointer pointer1 = new Memory(2*Short.SIZE); 
    pointer1.setShort(0,(short)1); 
    pointer1.setShort(Short.SIZE,(short)2); 
    
    Pointer pointer2 = new Memory(2*Short.SIZE); 
    pointer2.setShort(0,(short)3); 
    pointer2.setShort(Short.SIZE,(short)4); 
    
    pointer.setPointer(0, pointer1); 
    pointer.setPointer(2*Short.SIZE, pointer2); 
    
    nativeLib.compute(new PointerByReference(pointer), 2,2); 
    

Ale pojawia in[0][0] = 3184 in[0][1] = 10460 in[1][0] = 3344 in[1][1] = 10460

Czy ktoś ma pomysł? Nie mogę zmienić podpisu C, mam do czynienia z tym krótkim **

Wielkie dzięki.

Rozwiązanie

I finnaly succed! w ten sposób:

 short[][] in = { 
      {1,2,3}, 
      {4,5,6}, 
    }; 

    Pointer[] data = new Pointer[in.length]; 
    for(int i=0;i<in.length;i++) { 
     data[i] = new Memory(2*Short.SIZE); 
     data[i].write(0, in[i], 0,in[0].length); 
    } 

    nativeLib.compute(data, in.length,in[0].length); 

z wynikiem:

in[0][0] = 1 
in[0][1] = 2 
in[0][2] = 3 
in[1][0] = 4 
in[1][1] = 5 
in[1][2] = 6 

Dzięki wielkie!

+0

Cieszę się, że wersja "tablicy wskaźników" zadziałała! –

Odpowiedz

2

JNA obsługuje tylko tablice jednowymiarowe.

Technicznie, podobnie jak C. short * może to być tablica 1d, 2d lub 3d. Nie wiedziałbyś, gdybyś nie wiedział, jakie są wewnętrzne elementy. Czy tylko czytając dokumentację wiesz, że funkcja oczekuje tablicy 2D. Wszystko, co naprawdę robisz, to przekazanie wskaźnika do pierwszego elementu tablicy (całkowita długość wiersza * col), a następnie użycie (rowIndex * col + colIndex) w celu pobrania wyniku. W JNA wystarczy dopasować tablicę 1D.

W tym przypadku jednak masz short **, więc wiesz, że masz tablicę wskaźników 1D, każdy wskaźnik wskazuje na tablicę 1D z short s. W JNA tworzysz tablicę wskaźników (Pointer[]) dla pierwszego *; każdy wskaże pierwszą "kolumnę" nowego wiersza (drugi *).

Błąd Invalid Memory Access wskazuje, że nie przydzielono prawidłowo pamięci rodzimej i daje mocną wskazówkę co do odpowiedzi: nie można po prostu przekazać prymitywnej tablicy jako parametru. Musisz przydzielić jego pamięć, używając klasy Memory lub włączając tablicę jako część Structure.

The new short[] {1, 2, 3, 4} tu nie pracuje, bo nie przydzielono pamięć native boczną wspierać pamięć java na tej tablicy. Byłaś na właściwej drodze dzięki alokacji pamięci, którą wykonałeś przy użyciu klasy Memory.

do C, short** in oczekuje tablicę wskaźników. Należy więc zacząć od deklarowania tablicę wskaźników:

Pointer[] p = new Pointer[row]; 

Potem ustawić wskaźniki dla każdego wiersza, przydzielania pamięci:

p[0] = new Memory(col * Native.getNativeSize(Short.TYPE)); 
p[1] = new Memory(col * Native.getNativeSize(Short.TYPE)); 

Teraz można napisać swoje wartości tablicy. Można iteracyjne nad kolumnami z offsetem i setShort() ale można też napisać bezpośrednio za pomocą Pointer.write() np

p[0].write(0, new short[] {1, 2}, 0, 2); 
p[1].write(0, new short[] {3, 4}, 0, 2); 

Wtedy można przejść p z natywnym C in.

+0

O pierwszym rozwiązaniu, zadzwoń "nativeLib.compute (new short [] {1, 2, 3, 4}, 2, 2);" daje a; "Wyjątek w wątku" główny "java.lang.Error: Nieprawidłowy dostęp do pamięci \t na com.sun.jna.Native.invokeVoid (Metoda natywna)" –

+0

Zaktualizowałem moją odpowiedź ... –

+0

Bardzo dziękuję za pomoc to almose ok, ale z obu zaktualizowanych rozwiązań wynik jest: 'w [0] [0] = 1 w [0] [1] = 2 w [1] [0] = 3200 w [1] [1 ] = 10525 " –