2016-05-24 1 views
5

JavaからC関数を呼び出すには、JNIを使​​用する必要があります。私は正常に別のデータ型(ネイティブ変数、ヘッダーファイル、共有ライブラリ、blahの曖昧さを作成する)を渡すときにこれを行うことができましたが、バイト配列で動作するようにすることはできません。ここに私のC関数です:Java Native Interfaceを使用して、char *を引数とするC関数にバイト配列を渡すにはどうすればよいですか?

#include <stdio.h> 
void encrypt(int size, unsigned char *buffer); 
void decrypt(int size, unsigned char *buffer); 

void encrypt(int size, unsigned char *buffer){ 
    for(int i=0; i<size; i++){ 
     unsigned char c = buffer[i]; 
     printf("%c",c); 
    } 
} 
void decrypt(int size, unsigned char *buffer){ 
    for(int i=0; i<size; i++){ 
     unsigned char c = buffer[i]; 
     printf("%c",c); 
    } 
} 

そして、ここに私のJavaコードです

class Tester{ 
    public native void encrypt(int size, char *buffer); 
    public native void decrypt(int size, char *buffer); 
    static{ 
    System.loadLibrary("buffer"); 
    { 
    public static void main(String[] args){ 
     Tester test = new Tester(); 
     String hello = "hello"; 
     byte[] byteHello = hello.getBytes(); 
     test.encrypt(5,byteHello); 
     test.decrypt(5,byteHello); 
    } 
} 
(私はこれからヘッダファイルを作成した後、私はヘッダファイルにJNIコードでC関数宣言を交換する必要があることを理解します)

Javaでchar *型がサポートされていないので、コンパイルしようとするとエラーが発生します。おそらく私はJavaのchar []に型を変更する必要がありますか?とにかく、私の目標は、Javaのバイト配列をC関数に渡し、バイト配列を反復して各要素を出力することです。

+0

java '' 'char'''と' 'char'''型は互換性がないので、' 'byte []' '' 'をCに渡してから各要素を –

+0

「Java Native Interfaceを使用して、char *を引数にとるC関数にバイト配列を渡すにはどうすればよいですか? - できませんが、バイト配列をJavaバイト配列を引数として取るC関数に渡すことができます。 – immibis

答えて

6

Java charおよびC charタイプは互換性がありませんので、byte[]をCに渡して、必要に応じて各エレメントを変換する方がよいでしょう。


これらの線に沿って何か:

Main.java:

//...Code to load library... 

public static void main(String[] args) { 
    passBytes("hello".getBytes()); 
} 

public static native void passBytes(byte[] bytes); 

のmain.c:

#include "Main.h" // Main.h is generated 

JNIEXPORT void JNICALL Java_Main_passBytes 
    (JNIEnv *env, jclass clazz, jbyteArray array) { 
    unsigned char* buffer = (*env)->GetByteArrayElements(env, array, NULL); 
    jsize size = (*env)->GetArrayLength(env, array); 

    for(int i = 0; i < size; i++) { 
     printf("%c", buffer[i]); 
    } 

    (*env)->ReleaseByteArrayElements(env, array, buffer, JNI_ABORT); 
} 

jbyteArrayは、スタブ型の、より多くの何物でもありませんで定義されている:

struct _jobject; 
typedef struct _jobject *jobject; 
typedef jobject jarray; 
typedef jarray jbyteArray; 

実際にはデータは含まれていません。多かれ少なかれメモリアドレスです。

要素を取得するには、であるのでGetByteArrayElementsに渡します。これは、VMにCスタイルの配列の要素を取得するように要求することができます。

同じことが配列の長さに対して行われます(コピーを作成するかどうかは関係ありません)。

VMには、アレイが完了したことを伝えます。 ReleaseArrayElementsと呼びます。

また、jbyteは、これだけunsigend char*代わりにjbyte*この場合に安全であるようGetByteArrayElementsの結果を用いて、signed charとして定義されます。

+0

もう少し説明すれば、これはより良い答えになります。あなたのコメントからのコピーは良いスタートですが、ネイティブメソッドで受け取ったJava配列はC配列ではないことにも言及する価値があります。適切なJNI関数を使用して実際のC配列を取得する必要があります。これは、ネイティブメソッドの実装全体にいくつかの追加要件を課します。 –

+0

@JohnBollinger提案していただきありがとうございます。私はOPが既にこれのほとんどを知っていたと思っています。しかし、何らかの方法で、私は時々他の人もこれを読むことを忘れています;) –

+1

リリース*機能の重要性は、JVMヒープ内のオブジェクトの固定を解除することです。配列要素は必ずしもGet *によってコピーされるわけではないので、JNI_ABORTは必ずしもJVM配列の変更を避けるわけではありません。それはコピーを持っていた時間を節約するだけです。 –

関連する問題