Как передать структуры C взад и вперед в Java-код в JNI?
у меня есть некоторые функции C, которые я вызываю через JNI, которые берут указатель на структуру, и некоторые другие функции, которые будут выделять/освобождать указатель на тот же тип структуры, так что немного легче иметь дело с моей оболочкой. Удивительно, но в документации JNI очень мало говорится о том, как обращаться со структурами C.
мой файл заголовка C выглядит так:
typedef struct _MyStruct {
float member;
} MyStruct;
MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
соответствующий файл оболочки JNI C содержит:
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);
}
...и наконец, соответствующий 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);
}
}
к сожалению, этот код аварийно завершает работу JVM сразу после нажатия createNewMyStruct()
. Я немного новичок в JNI и понятия не имею, в чем проблема.
редактировать: я должен отметить, что код C очень ванильный C, хорошо протестирован и был перенесен из рабочего проекта iPhone. Кроме того, этот проект использует платформу Android NDK, которая позволяет запускать собственный код C из проекта Android из JNI. Однако Я не думайте, что это строго проблема NDK... это похоже на ошибку настройки/инициализации JNI с моей стороны.
4 ответов
нужно создать Java-класс с теми же элементами как C структуры, и "карта" их в код на C с помощью методов ОКР->GetIntField, ОКР->SetIntField, ОКР->GetFloatField, ОКР->SetFloatField, и так далее - короче, много ручного труда, надеюсь, уже существуют программы, которые делают это автоматически: JNAerator (http://code.google.com/p/jnaerator) и бухла (http://www.swig.org/). Оба имеют свои плюсы и минусы, выбор остается за вами.
это сбой, потому что Java_com_myorg_MyJavaClass_createNewMyStruct
объявляется return jobject
, но на самом деле возвращает struct MyStruct
. Если вы запустили это с включенным CheckJNI, VM будет громко жаловаться и прерываться. Ваш processData()
функция также будет довольно расстроена тем, что она получает arguments
.
A jobject
объект в управляемой куче. Он может иметь дополнительный материал до или после объявленных полей, и поля не должны быть выложены в памяти в определенном порядке. Так вы не можете сопоставить структуру C поверх класса Java.
самый простой способ справиться с этим был определен в более раннем ответе: манипулировать jobject
с функциями JNI. Выделите объекты из Java или с помощью NewObject
, Get
/Set
поля объекта с соответствующими вызовами.
существуют различные способы "накрутки" здесь. Например, вы можете включить byte[]
в вашем объекте Java, который содержит sizeof(struct MyStruct)
байты, а затем используйте GetByteArrayElements
получить указатель на он. Немного уродливо, особенно если вы хотите получить доступ к полям со стороны Java.
структура C представляет собой набор переменных (некоторые из них являются указателем функции). Переход на java-не очень хорошая идея. В общем, проблема в том, как передать более сложный тип java, например pointer.
в книге JNI рекомендуется сохранить указатель/структуру в native и экспортировать манипуляции на java. Вы можете прочитать несколько полезных статей. руководство и спецификация программиста родного интерфейса JavaTM, Я читал. 9.5 Сверстников Классы есть решение справиться с этим.
- сделайте класс на обеих сторонах Java и c++, просто поместив переменные-члены. Структуры C++ - это просто классы с открытыми членами данных. Если вы действительно в чистом C, прекратите читать теперь.
- используйте IDE(Ы), чтобы автоматически создавать сеттеры и геттеры для переменных-членов.
- используйте javah для создания файла заголовка C из класса Java.
- сделайте некоторое редактирование на стороне C++, чтобы сеттеры и геттеры соответствовали сгенерированному заголовку файл.
- введите код JNI.
это не идеальное решение, но это может сэкономить вам немного времени, и это, по крайней мере, даст вам скелет, который вы можете редактировать. Эта функциональность может быть добавлена в IDE, но без большого спроса это, вероятно, не произойдет. Большинство IDE даже не поддерживают смешанные языковые проекты, не говоря уже о том, чтобы они разговаривали друг с другом.