5.4. Java・Cとネイティブ型の対応

注記

詳細は「表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