2016-09-14 4 views
2

私が開発していた間に、誤って関数にパラメータを追加していませんでした。しかし、ネイティブjni呼び出しの同じ関数にはパラメータがあります。しかし、まだそれはjavaから正確なメソッドを呼び出しています。方法はJNIで識別されていますか?

JavaクラスDemo.java

package jniexamples.rmi; 

class Demo { 
    private native void jBoolean(); 
    public static void main(String[] args) { 
     new Demo().jBoolean(); 
    } 
    static { 
     System.load("jnidemo.so"); 
    } 
} 

Demo.c

#include <jni.h> 
#include <stdio.h> 
JNIEXPORT void JNICALL 
Java_jniexamples_rmi_Demo_jBoolean(JNIEnv *env, jobject ob,jint dtype) 
{ 
    printf("first demo %d" , dtype); 
    return; 
} 

結果:最初のデモ-1579007728

私は混乱してメソッドのシグネチャが異なっていても、それはどのようにJNIメソッドを呼び出しているのですか?

+0

は、不足しているパラメータの値が未定義になっているようです。 – Thilo

+0

メソッドはその名前で識別されます。署名が一致していることを確認する必要があります。 – Thilo

+1

IIRRの場合、適切な関数プロトタイプ –

答えて

2

Cの関数は、リンク時および実行時にのみ名前で識別されるため、Javaはその関数を呼び出しますが、引数は指定しません。

C関数を呼び出すときに引数が少なすぎると、未定義のビヘイビアが呼び出されます。何も起こらない可能性があります。 (あなたの場合、一見無作為な値が得られます)。

javahで生成されたヘッダーファイルには、正しい署名付き関数の宣言があります。生成されたヘッダをインクルードすると、コンパイラはヘッダ内のシグネチャと.cファイル内のシグネチャを比較でき、それらが異なる場合、コンパイル時にエラーが発生します。

+0

ありがとう、私はJniとCの新人です。しかし、このようなシナリオでは、ヘッダーファイルはどのように役立ちますか? – Nilesh

+1

@Nilesh生成されたヘッダファイルには、正しい署名付き関数の宣言があります。生成されたヘッダをインクルードすると、コンパイラはヘッダー内のシグネチャと.cファイル内のシグネチャを比較することができ、それらが異なる場合、コンパイル時にエラーが発生します。 –

1

非常に簡単なシナリオが次のように見えます。 javaからjBoolean()を呼び出すと、JVMはこのメソッドがネイティブであることに気付き、その実装を見つけようとします。あなたのケースでは、JVMはクラスとパッケージ名でjBooleanの飾りを付けてネイティブ関数の名前を構築します。結果は文字列Java_jniexamples_rmi_Demo_jBooleanです。次に、プロセスのアドレス空間にあるこの名前の関数をdlsym()と検索しようとします。このため、ネイティブモジュールを呼び出す前に、ネイティブモジュールをロードすることが重要です。そして、それがOKであれば - dlsym()は関数へのポインタを返しますが、このポインタには実際の関数の署名に関する情報はなく、ネイティブシグネチャを推測し、javaで宣言されたもののみを使用します。次に、JVMは、推論された署名に従ってネイティブ関数を呼び出します。

結果として、推測された署名と実際の署名との違いは、未定義の動作を引き起こし、ランダムなパラメータ値だけでなく、非常に奇妙なことにつながる可能性があります。このため、ネイティブの実装にjavahで生成されたヘッダーを含めることをお勧めします。このようなヘッダーは、実装の1つがヘッダーで宣言されたものと異なるシグニチャーを持つ場合、コンパイルをエラーで中断します。

+0

ありがとうSerhio、そのJVMがネイティブ関数にJava関数をマップする方法について私を明確に、また、ヘッダーファイルの使用 – Nilesh

関連する問題