Ajuda com JNI e Ponteiros em C [RESOLVIDO]

Pessoal, alguém pode me ajudar com o pedaço de código abaixo?


#include <jni.h>
#include <stdio.h>
#include "Prompt.h"
//Chama o tipo string da biblioteca JNI
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
    char buf[128];
    const jbyte *str;
    //Não entendi a linha abaixo:
    str = (*env)->GetStringUTFChars(env, prompt, NULL);
}

Env é um ponteiro que aponta para o método GetStringUTFChars(lê strings no formato UTF-8), da biblioteca jni.
Alguém sabe me dizer o que significa esse "(*env)->"?  Eu sei que em C, as setas e os pontos relacionados a um ponteiro chamam o que está depois deles.
Mas não entendi o que se passa naquela linha exatamente. Se alguém puder me ajudar, agradeço.

No JNIEnv, nele tem o método GetStringUTFChars(env, prompt, NULL).

Quando você usa o JNIEnv *env você usa o operador [quote]->[/quote], quando você usa o JNIEnv env você usa [quote].[/quote] para acessar os métodos e atributos.

-> e . são operadores de seleção de membros, assim como o . é em Java.

A diferença é que -> seleciona a partir do ponteiro para o objeto, enquanto . seleciona a partir do próprio objeto.

Então o segredo está na diferença entre “JNIEnv *env” e “JNIEnv env”. *env é um ponteiro e env seria só uma estrutura. Logo, devo usar a -> para atribuir valor a um atributo da estrutura por meio do ponteiro, e o operador “.” para passar um valor direto a um atributo da estrutura, o que seria equivalente a um membro static no Java, isso mesmo?

Se for isso, essa parte eu entendi, só não saquei direito o que se passa naquela linha.

Olhando com mais cuidado o jni.h.

Em C "p->m" é uma abreviação para "(*p).m".

No seu caso, você tem isto aqui:

(*env)->GetStringUTFChars

onde env é do tipo "JNIEnv *"

env : tipo JNIEnv*

*env : tipo JNIEnv (que é definido como
typedef const struct JNINativeInterface_ *JNIEnv;

Ou seja, JNIEnv é um tipo ponteiro (mais propriamente um const *) que aponta para um struct do tipo JNINativeInterface_.

(env)->GetStringUTFChars equivale a ((*env)).GetStringUTFChars, ou seja, está pegando um membro de JNINativeInterface_ chamado GetStringUTFChars (a definição dele é:

const char* (JNICALL *GetStringUTFChars)
      (JNIEnv *env, jstring str, jboolean *isCopy);

Ou seja, é um ponteiro para um método que recebe 3 parâmetros: (JNIEnv *env, jstring str, jboolean isCopy)
e retorna um parâmetro const char
.

Como em C é possível chamar um ponteiro de função como se fosse uma função, então você pode chamar o tal método GetStringUTFChars que está implementado, em C, em algum lugar. Note que em C não existem classes, quanto mais métodos virtuais; então foi por isso que foi feita toda essa "salada" de você chamar o método através de um ponteiro de função.

Huuuum, agora deu uma clareada na minha cabeça. Que salada heim. Puta complicação esse JNI, e olha que eu tô no começo, rsrs Mas agora as coisas fizeram mais sentido. Obrigado a todos mais uma vez.

Só mais uma pergunta: Isso acontece porque JNIEnv é um ponteiro que aponta para um local que tem outros ponteiros para funções da biblioteca JNI, como eu disse antes?
Por isso o *env pode referenciar, digo, chamar uma função?

O velho C

Olhei em alguns exemplos e pelo que entendi.

O env é o próprio ponteiro, o segundo prompt é a string de entrada, como em C não tem o tipo String é criado uma variável *str do tipo jbyte, o restante o método se encarrega de fazer a conversão, depois é só usar o printf do C para imprimir o conteúdo da variável str.

Quando você usa * você tem uma refêrencia do objeto (um endereço na memória) e o . é uma referencia, não tem nada a ver com static do java.

Exatamente. Quando o JNI é inicializado, a JVM cria uma estrutura contendo esses ponteiros de funções. Essa estrutura é o “environment” e o JNIEnv é um tipo que é um ponteiro para essa estrutura.

Muito bom pessoal, muito bom mesmo. Olha, mais uma vez muito obrigado. Agora eu posso estudar JNI em paz.
Obrigado a todos.

Vou dar um exemplo.

// Um método tradicional...
long teste(int x) {
    printf ("Hello, world");
    return -2;
}

// Definindo uma struct que contém um ponteiro para um método que recebe 1 parâmetro int e retorna 1 long
struct Env {
    long (*pTeste)(int);
};

// Definindo o tipo "ponteiro para Env"

typedef Env* PENV;

int main (int argc, char *argv[]) {
     Env env; 
     env.pTeste  = teste; // atribuindo o ponteiro de função
     PENV pEnv = &env;
     pEnv->pTeste (3);  // Chamando a função
     (*pEnv->pTeste) (3); // outra forma de chamar a a função
}

Valeu de novo. Ótimo exemplo.