함수를 호출하고 반환받는 과정이에 필수적으로 argument 를 사용하게 된다.

JNI 에서는 argument 로 기본 변수형, 배열, 객체형까지 모든 타입을 지원하는데, 두 랭귀지간에 변수를 전달하는 과정에서,

변수mapping 절차를 정확히 알아야 올바르게 사용할 수 있다.


===== (2) 기본 변수형 다루기 =========================================================


1. JNI-Types


java 에서 전달받은 기본형의 변수는 c/c++ 에서 jXXX 타입의 변수로 바로 사용이 가능하다.

jni.h 와 jni_md.h 에서 정확한 선언을 확인할 수 있다.


/usr/lib/jvm/java-6-openjdk/include/jni.h

............... 


  51 /*

  52  * JNI Types

  53  */

  54 

  55 #ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H

  56 

  57 typedef unsigned char   jboolean;

  58 typedef unsigned short  jchar;

  59 typedef short           jshort;

  60 typedef float           jfloat;

  61 typedef double          jdouble;

  62 

  63 typedef jint            jsize;


...............


/usr/lib/jvm/java-6-openjdk/include/linux/jni_md.h

..............


 33 typedef int jint;

 34 #ifdef _LP64 /* 64-bit Solaris */

 35 typedef long jlong;

 36 #else

 37 typedef long long jlong;

 38 #endif

 39 

 40 typedef signed char jbyte;




2. 함수 선언


native 함수에 argument 가 추가되면 javah 로 헤더파일을 생성했을 때, C 함수 선언에도 argument 가 추가되는 것을 확인할 수 있다. 또한 반환값에 따라서 선언도 달라진다.

public static native int primitivePrint2(int it, long lg, float ft, double db);

-->

JNIEXPORT jint JNICALL Java_Primitive_primitivePrint2(JNIEnv *, jclass, jint, jlong, jfloat, jdouble);


3. 예제 소스


MainStart.java

public class MainStart {

        public static void main(String[] args) {

                System.out.println("start...");


                boolean bl = true;

                byte    bt = (byte)0x55;

                char    ch = 'z';

                short   st = 1234;

                int             it = 123456;

                long    lg = 12345678;

                float   ft = 1234.56f;

                double  db = 1234.5678;


                int ret1 = Primitive.primitivePrint1(bl, bt, ch, st);

                int ret2 = Primitive.primitivePrint2(it, lg, ft, db);


                System.out.println("return values : " + ret1 + " , " + ret2);

        }


Primitive.java 

public class Primitive {

        static {

                System.loadLibrary("mylib");

        }


        public static native int primitivePrint1(boolean bl, byte bt, char ch, short st);

        public static native int primitivePrint2(int it, long lg, float ft, double db);


}


Primitive.cpp

#include <jni.h>

#include <stdio.h>


#ifdef __cplusplus

extern "C" {

#endif


JNIEXPORT jint JNICALL Java_Primitive_primitivePrint1(JNIEnv *env, jclass cls, jboolean jbl, jbyte jbt, jchar jch, jshort jst)

{

        if(jbl == JNI_TRUE)

                printf("boolean\t: true\n");

        else if(jbl == JNI_FALSE)

                printf("boolean\t: false\n");

        printf("byte\t: 0x%x\n", jbt);

        printf("char\t: %c\n", jch);

        printf("short\t: %d\n", jst);


        return 0;

}


JNIEXPORT jint JNICALL Java_Primitive_primitivePrint2(JNIEnv *env, jclass cls, jint jit, jlong jlg, jfloat jft, jdouble jdb)

{

        printf("int\t: %d\n", jit);

        printf("long\t: %lld\n", jlg);

        printf("float\t: %0.2f\n", jft);

        printf("double\t: %0.4f\n", jdb);


        return 1;

}


#ifdef __cplusplus

}

#endif


* javah 로 생성되는 Primitive.h 는 함수 선언을 확인하는 것을 제외하면 크게 필요한 것은 아니다. 함수 선언도 익숙해지면 javah 의 도움없이 만들수 있다. 그러므로 이 과정은 앞으로 생략한다.


컴파일 & 실행.

$ javac Primitive.java

$ javac MainStart.java

$ g++ -shared -o libmylib.so Primitive.cpp -I/usr/lib/jvm/java-6-openjdk/include/ -I/usr/lib/jvm/java-6-openjdk/include/linux/

$

$ export LD_LIBRARY_PATH=./

$ java MainStart 

start...

boolean : true

byte    : 0x55

char    : z

short   : 1234

int     : 123456

long    : 12345678

float   : 1234.56

double  : 1234.5678

return values : 0 , 1


위와같이 java native function 을 통해서 c/c++ 함수에 argument 를 전달하고 return value 를 받을 수 있다.

그러나 c/c++ 의 변수 type, 길이와 JNI-Type 변수의 type, 길이가 똑같이 매치하지는 않는다 점을 유의해야한다.

jchar 는 unsigned short 이고, jlong 은 32bit, 64bit 에 따라 long long 과 long 로 typedef 된다.


===========================================================================