Как передать структуры 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 и понятия не имею, в чем может быть проблема.
Edit: я должен отметить, что код 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
объявляется для возвратаjobject
, но на самом деле возвращает structMyStruct
. Если вы запустили это с включенным CheckJNI, виртуальная машина будет громко жаловаться и прерываться. ВашprocessData()
функция также будет довольно расстроен о том, что он получает в рукиarguments
.A
jobject
объект в управляемой куче. Он может иметь дополнительный материал до или после объявленных полей, и поля не должны быть выложены в памяти в каком-либо определенном порядке. Так вы не можете сопоставить структуру C поверх класса Java.самый простой способ справиться с этим был определен в более раннем ответе: манипулировать
jobject
с функциями JNI. Выделите объекты из Java или с помощьюNewObject
,Get
/Set
поля объекта с соответствующими вызовами.есть различные способы "обмануть" здесь. Например, вы можете включить
byte[]
в вашем объекте Java, который содержитsizeof(struct MyStruct)
байт, а затем использоватьGetByteArrayElements
получить указатель на оно. Немного некрасиво, особенно если вы хотите получить доступ к полям из стороны Java, а также.
структура C-это набор переменных (некоторые из них являются указателем функции). Пас на Java-это не очень хорошая идея. В общем, это проблема, как передать более сложный тип java, как указатель.
в книге JNI рекомендуется сохранить указатель/структуру в родном языке и экспортировать манипуляции на java. Вы можете прочитать некоторые полезные статьи. руководство и спецификация программиста родного интерфейса JavaTM, Я читал. 9.5 Сверстников Классы есть решение справиться с этим.
- сделайте класс на обеих сторонах Java и C++, просто поставив переменные-члены. Структуры C++ - это просто классы с открытыми членами данных. Если вы действительно находитесь в чистом C, прекратите читать сейчас.
- используйте IDE(Ы), чтобы автоматически создавать сеттеры и геттеры для переменных-членов.
- используйте javah для создания файла заголовка C из класса Java.
- сделайте некоторое редактирование на стороне C++, чтобы сеттеры и геттеры соответствовали сгенерированному заголовку файл.
- введите код JNI.
это не идеальное решение, но оно может сэкономить вам немного времени, и это, по крайней мере, даст вам скелет, который вы можете редактировать. Эта функциональность может быть добавлена в IDE, но без большого спроса это, вероятно, не произойдет. Большинство IDE даже не поддерживают смешанные языковые проекты, не говоря уже о том, чтобы они разговаривали друг с другом.