Jak předat C structs tam a zpět do kódu v jazyce Java v JNI?

hlasů
55

Mám nějaké funkce C, která Volám přes JNI, které berou ukazatel na strukturu, a některé další funkce, které bude přidělovat / Volný ukazatel na stejný typ konstrukce, takže je to trochu jednodušší řešení se svým obalem , Překvapivé je, že dokumentace JNI říká velmi málo o tom, jak se vypořádat s C struktur.

Moje hlavička C soubor vypadá takto:

typedef struct _MyStruct {
  float member;
} MyStruct;

MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);

Odpovídající JNI C obálka soubor obsahuje:

JNIEXPORT jobject JNICALL
Java_com_myorg_MyJavaClass_createNewMyStruct(JNIEnv *env, jobject this) {
  return createNewMyStruct();
}

JNIEXPORT void JNICALL
Java_com_myorg_MyJavaClass_processData(JNIEnv *env, jobject this, jintArray data,
                                       jint numObjects, jobject arguments) {
  int *actualData = (*env)->GetIntArrayElements(env, data, NULL);
  processData(actualData, numObjects, arguments);
  (*env)->ReleaseIntArrayElements(env, data, actualData, NULL);
}

... a nakonec odpovídající třída Java:

public class MyJavaClass {
  static { System.loadLibrary(MyJniLibrary); }

  private native MyStruct createNewMyStruct();
  private native void processData(int[] data, int numObjects, MyStruct arguments);

  private class MyStruct {
    float member;
  }

  public void test() {
    MyStruct foo = createNewMyStruct();
    foo.member = 3.14159f;
    int[] testData = new int[10];
    processData(testData, 10, foo);
  }
}

Bohužel, tento kód havaruje JVM právo po nárazu createNewMyStruct(). Jsem trochu nový aby JNI a nemají žádnou představu, co může být problém.

Edit : Musím poznamenat, že C kód je velmi vanilka C, je osvědčené a byl portován z projektu pracovního iPhone. Také tento projekt používá rámce Android NDK, který umožňuje spouštět nativní kód C z projektu Android zevnitř JNI. Nicméně, já si nemyslím, že to je přesně problém NDK ... Vypadá to, že chyby nastavení / inicializace JNI z mé strany.

Položena 13/10/2010 v 12:53
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
37

Musíte vytvořit třídu Java se stejnými členy jako C struct, a 'mapa' je v kódu C pomocí metody env-> GetIntField, env-> SetIntField, env-> GetFloatField, env-> SetFloatField, a tak dále - Stručně řečeno, spousta ruční práce, doufejme, že již existují programy, které to dělá automaticky: JNAerator ( http://code.google.com/p/jnaerator ) a SWIG ( http://www.swig.org/ ). Oba mají své výhody a nevýhody, volba je na vás.

Odpovězeno 13/10/2010 v 13:46
zdroj uživatelem

hlasů
8

Je to shazovat, protože Java_com_myorg_MyJavaClass_createNewMyStruct je deklarována vrátit „jobject“, ale je ve skutečnosti vrácení struct MyStruct. Pokud jste spustili tento se zapnutou CheckJNI VM by si stěžují, hlasitě a přerušit. Vaše funkce processData () bude také být docela naštvaný, co se dostane odevzdané „argumenty“.

Jobject je objekt na spravovaném haldy. To může mít další věci před nebo po deklarovaných polí a pole se nemají být stanoveny v paměti v libovolném pořadí. Takže nelze mapovat C struct na vrcholu třídy Java.

Nejjednodušší způsob, jak se vypořádat s tím bylo zjištěno v předchozí odpovědi: manipulovat jobject s JNI funkcí. Alokovat objekty z Javy nebo s NewObject, Get / Set object pole s příslušnými hovorů.

Existují různé způsoby, jak se „podvádět“ zde. Například byste mohli zahrnout do Java objektu byte [], u kterého je sizeof (struct MyStruct) bajtů a potom použít GetByteArrayElements získat ukazatel na něj. Trochu ošklivá, zvláště pokud chcete získat přístup k polí ze strany Java stejně.

Odpovězeno 14/10/2010 v 00:37
zdroj uživatelem

hlasů
6

C struktura je kolekce proměnných (některé jsou ukazatel funkce). Přecházejí na Java není dobrý nápad. Obecně platí, že se jedná o problém, jak předat složitější typu Java, jako ukazatel.

V JNI knize, aby ukazatel / strukturu přirozené a exportní manipulace Java je doporučeno. Můžete si přečíst některé užitečné články. The JavaTM tomuto rozhraní programátora Guide a specifikace, jsem si přečetl. 9.5 Peer Třídy máme řešení vypořádat se s ním.

Odpovězeno 23/10/2010 v 03:30
zdroj uživatelem

hlasů
-1
  1. Udělat třídu na obou Java a C ++ stranách, jen uvedení v členských proměnných. C ++ structs jsou opravdu jen třídy s členy veřejných dat. Pokud jste opravdu v čistém C, přestat číst.
  2. Použijte svůj IDE (y), aby se setters a příjemcové pro členské proměnné automaticky.
  3. Použijte javah generovat soubor záhlaví C ze třídy Java.
  4. Dělat nějaké úpravy na C ++ strany, aby se tvůrci a getry odpovídat souboru generované záhlaví.
  5. Vložit do kódu JNI.

To není ideální řešení, ale to vám může ušetřit trochu času, a to bude alespoň vám kostru, které můžete upravovat. Tato funkce může být přidán do IDE, ale bez velkého poptávky, to asi nebude dít. Většina IDE ani podporovat smíšené jazykové projekty, natož pak s nimi mluvit k sobě navzájem.

Odpovězeno 08/05/2013 v 13:27
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more