Вызовы JNI разные в C и C++?

Итак, у меня есть следующий код на C, который использует собственный интерфейс Java, однако я хотел бы преобразовать его в C++, но не знаю, как это сделать.

 #include <jni.h>
 #include <stdio.h>
 #include "InstanceMethodCall.h"

 JNIEXPORT void JNICALL 
 Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
 {
     jclass cls = (*env)->GetObjectClass(env, obj);
     jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
     if (mid == NULL) {
         return; /* method not found */
     }
     printf("In C\n");
     (*env)->CallVoidMethod(env, obj, mid);
 }

Java-программа:

 class InstanceMethodCall {
     private native void nativeMethod();
     private void callback() {
         System.out.println("In Java");
     }
     public static void main(String args[]) {
         InstanceMethodCall c = new InstanceMethodCall();
         c.nativeMethod();
     }
     static {
         System.loadLibrary("InstanceMethodCall");
     }
 }

Каковы различия, в которых JNI взаимодействует с C и C++? Любая помощь приветствуется.

Спасибо, Пит.


person Petey B    schedule 01.06.2009    source источник
comment
Что не так с вышеизложенным? Для меня это выглядит как действительный код C++.   -  person jalf    schedule 01.06.2009
comment
Проголосовал за хорошо построенный пример. Красиво сказано.   -  person Paul Morie    schedule 02.06.2009
comment
Спасибо например на C, в котором я ищу. Для C++ вы можете взглянуть на этот пример (хотя и в SDL2), но он будет передавать использование wiki.libsdl.org/.   -  person haxpor    schedule 10.10.2018


Ответы (4)


Раньше у меня была книга Essential JNI. И хотя он немного устарел, большая часть его работает и по сей день.

Если я правильно помню, в C конструкции Java — это просто указатели. Таким образом, в вашем коде "(*env)->" разыменовывает указатели, чтобы предоставить вам доступ к базовым методам.

Для C++ "env" на самом деле является объектом - сущностью, отличной от указателя C. (И JNI может фактически предоставить реальные объекты для вашего кода C++ для манипулирования, поскольку C++ фактически поддерживает объекты.) Таким образом, «env->» имеет другое значение в C++, это означает «вызвать метод, который содержится в объекте, на который указывает «env». ".

Другое отличие, я считаю, заключается в том, что многие функции C-JNI требуют, чтобы один из ваших параметров был "JNIEnv *env". Итак, в C вам, возможно, придется сказать (*env)->foo(env, bar). В С++ вторая ссылка на "env" не нужна, поэтому вместо этого вы можете сказать "env->foo(bar)"

К сожалению, у меня нет этой книги передо мной, поэтому я не могу это подтвердить! Но я думаю, что изучение этих двух вещей (в частности, поиск их в Google или в другом коде JNI) поможет вам довольно далеко.

person poundifdef    schedule 01.06.2009
comment
Значит, JNI может работать как с C, так и с C++? Я этого не знал (но, может быть, это и не удивительно, так как я никогда не использовал JNI: p). - person Michael Myers; 01.06.2009
comment
(ха-ха, спасибо за исправление моей уценки!) Ага; интерфейс ведет себя одинаково - код C и C++ /в основном/ изоморфен, и на практике единственная разница заключается в синтаксисе. - person poundifdef; 01.06.2009

Основное различие между вызовами JNI в C и CPP заключается в следующем:

JNI в стиле C выглядит как (*env)->SomeJNICall(env, param1...)

JNI в стиле C++ выглядит как env->SomeJNICall(param1...)

поэтому, чтобы преобразовать его в CPP, вам нужно сделать

Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
    jclass cls = env->GetObjectClass(obj);
    jmethodID mid = env->GetMethodID(cls, "callback", "()V");
    if (mid == NULL) {
        return; /* method not found */
}
printf("In C++\n");
env->CallVoidMethod(obj, mid);
//rest of your code

Кроме того, убедитесь, что ваши функции JNI соответствуют соглашению об именах.

Пример:

JNIEXPORT jint JNICALL Java_com_shark_JNITestLib_JNITestLib_startServer(JNIEnv* env, jobject o, jstring inputName, jstring streamName, jstring description) {

Вы можете видеть, что соглашение Java_(имя пакета) _ (имя класса) _ (имя метода)

так как тот, что выше, использовался в классе, например

package com.shark.JNITestLib

import java.util.stuff;

public class JNITestLib 
{
    static
    {
        System.loadLibrary("myJNIlib");
    }

    public native synchronized int startServer(String inputName, String streamName, String description);

//more class stuff...
}

При работе с JNI я принял соглашение называть класс, содержащий вызовы JNI, тем же именем, что и пакет. Вот почему вы видите JNITestLib дважды (и именно поэтому мой JNI работает сразу же, потому что я всегда забываю, как правильно называть вызовы JNI)

Приветствую, надеюсь помог :)

person Shark    schedule 01.02.2012

Вы пытались обернуть свой код C в файл extern "C". Дополнительные сведения см. в разделе C++ Faq Lite. для других возможных механизмов, позволяющих вам использовать ваш код C с C++.

person Brian    schedule 01.06.2009
comment
Я думаю, что это, вероятно, проблема. JNI ожидает код C, поэтому он, вероятно, получает ошибки компоновки. - person Michael Myers; 01.06.2009
comment
Ярп. Имена, вероятно, искажаются в компиляторе C++. Добавьте extern C { ‹ваш код› }. - person Kieveli; 01.06.2009
comment
Почему вы хотите обернуть код C++ как C и использовать уродливый синтаксис C, когда вы можете напрямую использовать более лаконичный синтаксис C++? - person rustyx; 13.04.2021
comment
@rustyx: при переносе кода можно выбрать семантический перенос (сохранить семантику, но использовать особенности и конструкции языка) или построчный перенос (изменить как можно меньше кода, в основном построчно, а не чем в целом). Семантический порт легче поддерживать и использовать. Построчный перенос проще сделать, и он упрощает использование любой существующей базы знаний, связанной с исходным кодом. Имейте в виду, что построчный перенос может привести к странным ошибкам, если вы попытаетесь перенести конструкцию на язык, который на самом деле ее не поддерживает. - person Brian; 13.04.2021
comment
Я также отмечу, что построчный порт, если он до неприличия прост (как в данном случае), является отличным способом предложить прототип для проверки того, что портируемая библиотека будет пригодна к использованию после того, как она будет портирована. - person Brian; 13.04.2021

Прошло некоторое время с тех пор, как я коснулся стандартного C++, но я все равно попробую.

"(*env)->" мне кажется странным. Разве это не должно быть просто "env->"?

Может быть, я ошибаюсь, и это должно работать, но зачем все усложнять?

person michael aubert    schedule 01.06.2009
comment
x-›y — это сокращение от (*x).y. Следовательно, (*env)-›y эквивалентно (**env).y, что отличается от (*env).y: происходит дополнительное разыменование. - person Adam Rosenfield; 01.06.2009
comment
Синтаксис разыменования я действительно знал. Позвольте мне быть более ясным: я просто далек от убеждения, что версия JNIEnv для C++ действительно требует двойного разыменования. - person michael aubert; 01.06.2009
comment
@michaelaubert См. stackoverflow.com/questions/67077815/. - person Leponzo; 13.04.2021