2014-01-04 3 views
1

Так что я обычно программирую в java и иди, поэтому мне жаль мое невежество, я изучил базовые c и C++. Однако, играя с JNI, я наткнулся на этот код C.C typedef, указывающий на функцию [c синтаксис]

(*env)->ReleaseStringUTFChars(env, javaString, nativeString); 

Мне было интересно, почему (* env) указывает на функцию. По моему пониманию, env - это просто структура и в C. Функции не зависят от переменной, как то, как классы работают на C++ и JAVA.

Я что-то пропустил в C, который позволяет функциям только для того, чтобы стрелять для структуры?

Вид как в Go

type House struct { } 

func (h House) GetHouseName() string { } //method defined outside of struct, but works on House 

К сожалению, я не знаю, как слово, что я ищу для вас Google не действительно оказался много, и книги, которые я заказанные на C обыкновение был в до следующей недели.

Спасибо за помощь!

+1

Вы правильны в замечании, что функции C не несут неявную область или 'this' объект вокруг. Вот почему вам нужно явно передать 'env' в качестве первого параметра в вызове метода (в большинстве языков OO это произойдет неявно) – hugomg

ответ

4

Нет, в вашем примере env должен быть указателем на указатель на структуру, содержащий указатель на функцию (!).

Нечто подобное:

struct MyEnvironment 
{ 
    void (*ReleaseStringUTFChars)(MyEnvironment **env, /*...*/); 
}; 

int main() 
{ 
    MyEnvironment *theEnv = AllocEnvironment(); 

    MyEnvironment **env = &theEnv; 

    (*env)->ReleaseStringUTFChars(env, ...); 
} 

(Несколько поиска Google позже ...)

Как это происходит, в JNI есть то, что мало ЬурейеЕ:

typedef const struct JNINativeInterface* JNIEnv; 

И env определяется как:

JNIEnv *env; 

Что, по-моему, является указателем на указатель на структуру.

Проблема с функциями C состоит в том, что им не хватает понятия функций-членов, поэтому они должны включать явный аргумент объекту, который вызывает эту функцию.

В JNI есть странный трюк прекомпилятора для работы как с C, так и с C++ с тем же заголовком и тем же двоичным интерфейсом, но совершенно другим синтаксисом. Например, ваш C вызов:

(*env)->ReleaseStringUTFChars(env, javaString, nativeString); 

В C++ будет:

env->ReleaseStringUTFChars(javaString, nativeString); 

Это будет работать, потому что в C++ env не указатель указатель на, но указатель на тип этого тип:

struct JNIEnv 
{ 
    const struct JNINativeInterface* functions; 

    /* inline function: no code generated */ 
    void ReleaseStringUTFChars(jstring string, const char* utf) 
    { 
     functions->ReleaseStringUTFChars(this, string, utf); 
    } 
    /* a lot of other functions... */ 
}; 

Поскольку этот класс имеет один член типа указатель на структуры, она совместима с двоичной таким указателем, который может бросить между с ++ и а JNIEnv C struct JNINativeInterface * без проблем.

1

JNIEnv (тип env) отличается для C и C++.

Если вы посмотрите на исходный код для JNI, вы увидите что-то вдоль этих линий:

#ifdef __cplusplus 
typedef JNIEnv_ JNIEnv; 
#else 
typedef const struct JNINativeInterface_ *JNIEnv; 
#endif 

Глядя на случай C первых, мы видим, что JNIEnv является указателем на структуру, содержащую кучу указатели на функции (я только включал пару примеров здесь):

struct JNINativeInterface_ { 
    jclass (JNICALL *FindClass)(JNIEnv *env, const char *name); 
    jfieldID (JNICALL *FromReflectedField)(JNIEnv *env, jobject field); 
    // ... 
} 

Так что для C, env является указателем на структуру указателей на функции. Когда вы разыскиваете env, вы получаете структуру, а затем вы разыскиваете указатель на функцию для вызова функции. Это объясняет линию (*env)->ReleaseStringUTFChars(env, javaString, nativeString);.

C++ версия использует структуру, состоящие из функций-членов, которые облегают struct JNINativeInterface_:

struct JNIEnv_ { 
    const struct JNINativeInterface_ *functions; 
    jclass FindClass(const char *name) { 
     return functions->FindClass(this, name); 
    } 
} 
Смежные вопросы