<JNI>자바에서 c언어 사용하기

 

자바의 제약사항

자바는 운영체제에 독립적이기 위하여 자바가상머신을 이용한다. 이는 운영체제에 독립적이라는 편의성을 제공하지만, 한편으론 운영체제에서 사용할 수 있는 모든 기능을 끌어와 쓸 수 없다는 단점이 존재한다. 또한 자바는 바이트 코드로 된 프로그램이기 때문에 c나 c++등의 프로그램으로 만들어진 기계어 코드에는 속도가 느릴 수 밖에 없다.

 

자바의 제약사항을 덜어주는 JNI란?

JNI는 자바 이외의 언어로 작성된 프로그램을 JVM 위에서 실행 할 수 있도록 인터페이스를 제공해 주는 것이다. 따라서 JNI를 활용하면, 자바에서는 일부분의 제약이 있었던 운영체제만의 좋은 기능을 활용 할 수 있을 뿐만이 아니라, 여러 시스템을 아우를 수 있다.

 

 

 

 

 

 

이클립스에서 java JNI 로 dll 로드를 시켜보자.

 

자바 JNI 의 원리는 다음과 같다.

1. 자바 소스 내에서 호출하려는 C함수에 대한 선언과 호출구문 dll 로드문을 작성한다.

2. native call 하려는 C함수에 대한 정의문 및 헤더파일을 작성한다.

3. 만들어진 C파일을 dll 빌드한다.

4. 빌드된 dll 을 자바에서 사용한다.

 

C에서 dll 로드를 시킬 때와 비슷한 구조를 보인다.

( C에서는 LoadLibrary(), GetProcAddress() 순으로 )

 

 

자바에서 system("cls"); 를 호출해보도록 하자.

 

시스템 함수를 호출 하다 보니 os에 종속적이게 되고,

java만의 각 플렛폼 별 호환성은 떨어지게 된다.

(dll 만 플렛폼에 맞추면 동작할 것 같기도 하다.)

 

 

 

먼저 아래와 같이 JNI 호출을 위한 코드를 작성해주자.

(호출할 함수 선언 및 dll 을 로드한다.)

 

위에서 함수 이름은 C로 작성한 dll 의 함수 이름이다.

static 으로 빼둔 건 loadLibrary 를 함수하기 위해도 있고,

객체 생성 할 때 마다 로드 할 필요가 없기 때문이다.

 

함수 호출 시엔 class 생성 후 인스턴스.함수이름() 으로 호출하면 된다.

단 한번의 호출이라면

new ClassName().함수이름();

( gc에 의해 알아서 객체를 해제한다. )

 

이클립스에선 저장만 해도 컴파일이 되기 때문에

경로의 bin/패키지명/ 으로 가게되면 class 파일이 생성되어 있다.

(만약 없으면 javac 로 소스를 컴파일 해줘야 한다.)

 

 

 

자바 헤더파일을 작성하자.

c 코드 작성 전 먼저 jni 헤더파일을 생성해줘야 한다.

이 때 javah 의 대상은 java 소스로 컴파일한 바이트 코드( 클래스명.class ) 이다.

javah bin/패키지명/ 에서 수행하도록 한다.

javah 패키지명.클래스명

 

헤더 파일이 만들어 진다면 jni_클래스명.h 파일이 생성된다.

 

Error : Could not find class file for 'HelloWorld'.

에러 발생 시 다음을 참고하자

( 클릭 )

 

 

다음은 dll 파일의 c코드 작성이다.

 

아까 만든 javah 파일을 열어서 확인해보면,

다음과 같이 작성되어 있는데 저 헤더를 그대로 가져와 사용해도 되며

필자는 빨간색으로 쳐진 함수 이름만 가져와 사용하도록 하겠다.

 

jni.h 파일을 include 하였고, 그 후 필요한 헤더들을 넣었다.

3 라인의 KOKW_Game_Config.h 같은 경우는 필자의 패키지명_클래스명.h 로 아까 만든 javah 파일의 이름이다.

 

그 후 함수선언 후에 필요한 구문을 작성한다.

함수 명의 경우는

 

JNIEXPORT void JNICALL Java_패키지명_클래스명_함수명(JNIEnv *, jobject)

 

빨간 부분만 변하는 것 같으며, 자바소스에서 선언해 둔 native 함수들마다 각각 정의를 해주면 될 것 같다.

(함수명이나 리턴형식 등 함수의 기본구조는 무시하면 동작을 하지 않는다.)

 

 

마지막 dll 을 생성할 차례이다.

보통 일반적으로 사용하는 vs 컴파일러의 경우

jni.h 파일과 아까 javah 로 생성한 헤더파일의 경로를 지정해줘야 한다.

그 후 추가 디렉터리 설정으로 jdk 위치를 잡아줘야 한다.

경로는 두가지를 설정해주도록 하는데 다음과 같다.


1. jdk설치경로\include

2. jdk설치경로\include\win32

 

그 후 소스를 보자.

 

이대로 컴파일을 하면 Java 에서 사용 가능한 dll 파일이 컴파일 된다.

 

 

 

 

 

다음으론 cl 컴파일러를 이용한 컴파일 방법에 대해 알아보도록 하겠다.

 

원하는 컴파일 비트의 도구를 실행한다.

(관리자 권한으로 실행해야 속 편하다.)

 

실행 후 "cl" 이란 명령어를 쳐보자.

 

cl 컴파일러가 정상적으로 실행된다.

 

그럼 dll을 빌드해보도록 하자.

 

cl –I "C:\jdk경로\include" –I"C:\jdk경로\include\win32" –LD "c소스 파일 위치" –FeDLL명.dll

 

빨간색 부분은 사용자마다 가변적인 부분이다.

각자 맞춰서 인자를 바꿔서 사용하도록 하자.

 

-I (대문자 'i') 옵션은 include 할 파일들의 디렉터리를 지정한다.

-LD 옵션은 dll 파일 생성 시 추가한다.

-Fe 옵션은 실행파일의 이름을 지정한 이름으로 바꿀 때 사용한다.

 

-I 옵션의 경우 띄어쓰기를 해도 되지만,

-Fe 옵션의 경우 띄어쓰기를 하지 않는게 맞는 명령어 이다.

 

 

마지막으로 dll 파일은 프로젝트의 루트경로에 복사해 두면

 

자바 내에서 dll 함수를 제대로 임포트하여 호출이 가능해진다.

문자 인코딩에 대해서 간략히 포스팅 해보자.

   

문자 인코딩에 대해서 이해를 해야한다.

ascii 코드를 알고 시작해야 한다.

   

ascii 코드라는건 알파벳 a~z, A~Z 와 각 특수문자 등등 128가지의 문자들을 정의 해 둔걸 말한다.

나중엔 이것마저 모자라 확장 ascii 까지 나오게 된다.

하지만 확장 ascii 라고 해봐야 표현할 수 있는 문자에 대해선 한계가 존재한다.

각 나라별로 언어가 다르니 문자 또한 다르게 되는데, 이걸 표현하기 위해서

DBCS(Double Byte Character Set)가 나오게 되었는데

이걸 이용하면 1바이트 혹은 2바이트로 구성된다.

첫번째 문자가 특정 범위 안에 속할 경우 하나의 문자를 결정하기 위해서

그 다음 바이트를 확인해야 했다.

   

이제는 C라이브러리나 윈도우 함수들이 유니코드를 지원하기 때문에 많이 편하다.

윈도우 비스타의 경우는 유니코드 문자를 UTF-16로 인코딩하게 되고

UTF-16 은 2바이트로 구성된다.

다른 인코딩 방법에 대해선

UTF-8 과 UTF-32 로 존재한다.

   

종류

디코딩 방법

UTF-8

한 문자를 표현하기 위해서 1~4 바이트의 가변적인 크기로 인코딩을 수행한다. 0x0080 미만의 경우 1바이트 0x0080과 0x07FF 사이라면 2바이트 등등 0x0800 이상의 문자는 3바이트 등으로 가변적인 크기를 가진다.

UTF-32

모든 문자를 4바이트로 인코딩한다. 문자 변환 알고리즘을 구현시엔 간단하지만 메모리 사용에 있어서 비효율적인 모습을 보인다.

  

'Programing > Basic' 카테고리의 다른 글

[Git] Git, GitHub, GitLab 은 뭐?, 또 버전관리란 무엇인가 ?  (0) 2017.01.20
기초) 컴퓨터 구조  (0) 2015.09.25
네트워크의 정의  (0) 2015.09.24

+ Recent posts