2009-06-01 12 views
23

Así que tengo el siguiente código en C que utiliza Java Native Interface, sin embargo, me gustaría convertir esto a C++, pero no estoy seguro de cómo.JNI Llamadas diferentes en C vs 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); 
} 

programa 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"); 
    } 
} 

¿Cuáles son las diferencias en el cual JNI interactúa con C y C++? Cualquier ayuda es muy apreciada.

Gracias, Pete

+1

¿Qué pasa con lo anterior? A mí me parece un código válido de C++. – jalf

+1

Voto arriba debido al ejemplo bien construido. Bien dicho. –

Respuesta

19

Solía ​​tener el libro Essential JNI. Y aunque está un poco anticuado, gran parte de él todavía funciona hoy.

Si no recuerdo mal, en C, las construcciones de Java son simplemente punteros. Por lo tanto, en su código, "(*env)->" está desmarcando punteros para darle acceso a los métodos subyacentes.

Para C++, "env" es en realidad un objeto, una entidad diferente de un puntero C. (Y JNI puede proporcionar objetos reales para manipular su código C++, ya que C++ realmente admite objetos). Por lo tanto, "env->" tiene un significado diferente en C++, significa "llamar al método que está contenido en el objeto al que apunta" env ".

la otra diferencia, creo, es que muchas de las funciones C-JNI requiere que uno de los parámetros de ser el 'JNIEnv *env'. Así que en C es posible que tenga que decir (*env)->foo(env, bar). con C++, la segunda referencia a "env" no es necesario, por lo que puede decir "env->foo(bar)"

Desafortunadamente, no tengo el libro anterior en frente mío, ¡así que no puedo confirmarlo! Jugar estas dos cosas (buscándolas específicamente en google o en otro código JNI) te llevará bastante lejos.

+0

Entonces, ¿JNI realmente puede manejar tanto C como C++? No lo sabía (pero tal vez eso no es sorprendente, ya que nunca he usado JNI: p). –

+0

(jaja, ty para arreglar mi rebaja!) Sí; la interfaz se comporta de la misma manera: el código C contra C++ es/básicamente/isomórfico, y en la práctica la única diferencia es la sintaxis. – poundifdef

-1

el primer código de una correcta C++, no es así? Entonces, ¡terminaste!

En serio, ¿qué quiere cambiar en ese código? ¿Por qué?

+0

cuando compilo el código anterior como .c funciona y funciona bien, cámbielo a .cpp y recibo una serie de errores –

+0

¿Luego publicamos los errores para que podamos ver qué es lo que se supone que debemos responder? ;) – jalf

+0

El código que publicó es el código C, y JNI + C requiere punteros. Sin embargo, al vincular Java y C++, JNI proporciona/objects/- en lugar de "punteros a estructuras que se comportan como objetos" - al idioma nativo. – poundifdef

5

Has intentado envolver tu código C en un extern "C". Consulte C++ Faq Lite para obtener más información y otros mecanismos posibles para permitirle usar su código C con C++.

+0

Creo que ese es probablemente el problema. JNI espera el código C, por lo que probablemente obtenga errores de enlace. –

+0

Yarp. Los nombres probablemente se destrocen en el compilador de C++. Agregue el C externo {}. – Kieveli

2

Ha pasado un tiempo desde que toqué C++ estándar pero voy a intentarlo de todos modos.

"(*env)->" me resulta extraño. ¿No debería ser simplemente "env->"?

Tal vez estoy equivocado y se supone que debe funcionar, pero ¿por qué complicar las cosas de todos modos?

+3

x-> y es la abreviatura de (* x) .y. Por lo tanto, (* env) -> y es equivalente a (** env) .y, que es diferente de (* env) .y: se produce una desreferencia adicional. –

+0

La sintaxis de desreferencia, en realidad lo sabía. Permítanme ser más claro: estoy muy lejos de estar convencido de que la versión C++ de JNIEnv realmente requiera la doble desreferenciación. –

4

La principal diferencia entre llamadas JNI en C y CPP es la siguiente:

C-estilo JNI parece (* env) -> SomeJNICall (env, param1 ...)

estilo

C++ JNI parece env-> SomeJNICall (param1 ...)

por lo que convertirlo a CPP que tiene que hacer

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 

Además, asegúrese de que sus funciones JNI siguen la convención de nomenclatura.

Ejemplo:

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

Se puede ver que la convención es Java_ (nombre de paquete) _ (nombre de clase) _ (methodname)

desde la de arriba fue utilizado en una clase como

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... 
} 

Al trabajar con JNI hice una convención para nombrar la clase que contiene llamadas JNI para que sea del mismo nombre que el paquete. Es por eso que se ven JNITestLib dos veces (y que por eso mi JNI trabaja la derecha del palo, porque siempre se me olvida cómo nombrar correctamente la llamadas JNI)

Saludos, espero que me ayudó a :)