강좌 & 팁
함수를 호출하고 반환받는 과정이에 필수적으로 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 된다.
===========================================================================