詳細は「表5.1「ネイティブレイヤーの型対応表」」と「表5.2「ライブラリがサポートする型(ネイティブレイヤーの処理前の対応)」」を参照ください。
JNAはJavaのプリミティブ型をC言語のデータ型に変換します。型の対応を真剣に考える必要があるJNIと比べると、JNAは比較的直感に近い型マッピングをします。
例えば、Javaのint型は、C言語のint型とマッピングされ、C言語のchar型は、Javaのbyte型にマップされます。このようにポインタ、配列を例外として、プリミティブ型に自動変換されます。
表5.1 ネイティブレイヤーの型対応表
型(C) | ネイティブ表現 | 型(Java) |
char | 8-bit整数 | byte |
wchar_t | プラットフォームに依存 | char |
short | 16-bit整数 | short |
int | 32-bit整数 | int |
int | booleanフラグ | boolean |
enum | enumeration型 | int (おおむね) |
long long, __int64 | 64-bit整数 | long |
float | 32-bit浮動小数点 | float |
double | 64-bit浮動小数点 | double |
pointer (例: void*) | プラットフォームに依存 (32- または 64-bitポインタ) | Buffer/Pointer |
pointer (例: void*),array | 32- or 64-bitポインタ、メモリの連続するブロック(structメンバー) | <P>[] (プリミティブ型配列) |
またjava.lang.Stringのようなデータ型についても、C言語の「const char*」に変換される等、事後的にキャストや明示的変換を必要としません。
表5.2 ライブラリがサポートする型(ネイティブレイヤーの処理前の対応)
型(C) | ネイティブ表現 | 型(Java) |
long | プラットフォームに依存 (32- or 64-bit integer) | NativeLong |
const char* | NULL終端配列 (ネイティブencodingまたはjna.encoding) | String |
const wchar_t* | NULL終端配列 (unicode) | WString |
char** | c文字列のNULL終端配列 | String[] |
wchar_t** | Cワイド文字列のNULL終端配列 | WString[] |
void** | ポインタのNULL終端配列 | Pointer[] |
struct* | struct(引数、戻り値)を指すstructポインタ等 | Structure |
union | Structureと同じ | Union |
struct[] | structの配列, メモリの連続するブロック | Structure[] |
void (*FP)() | 関数ポインタ | Callback |
pointer (<T> *) | Pointerと同じ | PointerType |
ポインタや配列を使うには、JNAのPointer型を使います。C言語の関数からポインタを受けた戻り値には抽象クラス「ByReference」を継承したサブクラスとして宣言します。
ByteByReference DoubleByReference FloatByReference IntByReference LongByReference NativeLongByReference PointerByReference ShortByReference
ちなみにこのByReferenceは、PointerTypeクラスのデータ型を指すポインタの機能を継承します。
public abstract class ByReference extends PointerType
このByReferenceのサブクラスであるByteByReferenceは、8ビット整数やchar型のメモリアドレスをポインタで渡す場合に使用できます。
public class ByteByReference extends ByReference
ではポインタを使ったJNAの実装例を見てみましょう。
まずC言語で、helloReplyという関数を作ってみましょう。
#include <stdio.h> #include <stdlib.h> #include <string.h> const char* helloReply(const char* msg) { printf("%s\n",msg); msg = "I'm from C language!"; return msg; }
この関数は文字列を引数とし、戻り値をcharを指すポインタとします。次にJavaでこの関数をマッピングしてみます。
interface HelloLib extends Library { HelloLib Instance = (HelloLib) Native.loadLibrary("hello", HelloLib.class); ByteByReference helloReply(String msg); } ...... ByteByReference reply = hello.helloReply("Hello World! JNA!"); Pointer ptr = reply.getPointer(); String str = ptr.getString(0); System.out.println(str);
インターフェース内でマップする関数を宣言した後に、ポインタを「getPointer()」関数で取得します。さらにポインタのデータを「getString()」関数で取り出しています。
Copyright 2018-2019, by Masaki Komatsu