ホームページ  >  記事  >  Java  >  Java の JNA 型マッピングの詳細と使用法への注意

Java の JNA 型マッピングの詳細と使用法への注意

王林
王林転載
2023-04-18 17:07:031306ブラウズ

String

最初は String のマッピングです。JAVA の String は、実際には 2 つのネイティブ型、const char* と const wchar_t* に対応します。デフォルトでは、文字列は char* に変換されます。

char は ANSI データ型で、wchar_t は Unicode 文字データ型で、ワイド文字とも呼ばれます。

JAVA の Unicode 文字を char 配列に変換する場合は、いくつかのエンコード操作を実行する必要があります。jna.encoding が設定されている場合は、設定されたエンコード方式がエンコードに使用されます。デフォルトでは、エンコード方式は「UTF8」です。

WString の場合は、エンコードせずに Unicode 値を WString に直接コピーできます。

最初に簡単な例を見てみましょう:

char* returnStringArgument(char *arg) {
  return arg;
}

wchar_t* returnWStringArgument(wchar_t *arg) {
  return arg;
}

上記のネイティブ コードは次のようにマッピングできます:

String returnStringArgument(String s);
WString returnWStringArgument(WString s);

別の例を見てみましょう。メソッドは次のようなものです:

int getString(char* buffer, int bufsize);

int getUnicodeString(wchar_t* buffer, int bufsize);

2 つのメソッドを定義しました。そのパラメータは char* と wchar_t* です。

次に、JAVA でメソッド マッピングを定義する方法を見てみましょう:

// Mapping A:
int getString(byte[] buf, int bufsize);
// Mapping B:
int getUnicodeString(char[] buf, int bufsize);

以下は具体的な使用法です:

byte[] buf = new byte[256];
int len = getString(buf, buf.length);
String normalCString = Native.toString(buf);
String embeddedNULs = new String(buf, 0, len);

JAVA では次のような疑問を持つ学生もいるかもしれません。文字列は char* に変換できますが、なぜここでバイト配列を使用する必要があるのでしょうか?

これは、getString メソッドが受信した char 配列の内容を変更する必要があるためですが、String は不変であるため、ここで String を直接使用することはできず、バイト配列を使用する必要があります。

次に、Native.toString(byte[]) を使用してバイト配列を JAVA 文字列に変換します。

別の戻り値の状況を見てください:

// Example A: Returns a C string directly
const char* getString();
// Example B: Returns a wide character C string directly
const wchar_t* getString();

一般に、ネイティブ メソッドが文字列を直接返す場合、マッピングに文字列を使用できます:

// Mapping A
String getString();
// Mapping B
WString getString();

ネイティブ コードが割り当てられた後の場合String のメモリ空間を必要とする場合は、以下に示すように、将来のある時点で占有空間を解放できるように、戻り値として JNA の Pointer を使用する方がよいでしょう:

Pointer getString();

バッファ、メモリ、配列およびポインタ

バッファとメモリを使用する必要があるのはどのような場合ですか?

一般に、基本データの配列がパラメータとして関数に渡される場合、基本クラスを JAVA 配列で直接使用できます。その代わり。ただし、メソッドが戻った後もネイティブ メソッドが配列にアクセスする必要がある場合 (配列へのポインタを保存する)、この場合、基本クラスの配列を使用するのは適切ではありません。この場合、ByteBuffers またはメモリ 。

JAVA の配列には長さがあることはわかっていますが、ネイティブ メソッドの場合、返される配列は実際には配列へのポインタであり、返される配列の長さはわかりません。そのため、ネイティブ メソッドの場合配列ポインタが返される場合、JAVA コードでのマッピングに配列を使用することは不適切です。この場合、Pointer を使用する必要があります。

Pointer はポインタを表します。まず Pointer の例を見てみましょう。最初はネイティブ コードです:

void* returnPointerArgument(void *arg) {
  return arg;
}

void* returnPointerArrayElement(void* args[], int which) {
  return args[which];
}

次は JAVA マッピングです:

Pointer returnPointerArgument(Pointer p);
Pointer returnPointerArrayElement(Pointer[] args, int which);

基本的なポインタに加えて、型指定されたポインタ (PointerType) もカスタマイズできます。以下に示すように、PointerType を継承するだけで済みます:

public static class TestPointerType extends PointerType {
            public TestPointerType() { }
            public TestPointerType(Pointer p) { super(p); }
        }
TestPointerType returnPointerArrayElement(TestPointerType[] args, int which);

文字列をもう一度見てください。配列:

char* returnStringArrayElement(char* args[], int which) {
  return args[which];
}
wchar_t* returnWideStringArrayElement(wchar_t* args[], int which) {
  return args[which];
}

対応する JAVA マッピングは次のとおりです:

String returnStringArrayElement(String[] args, int which);

WString returnWideStringArrayElement(WString[] args, int which);

バッファに対応して、JAVA NIO は ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer などの多くのタイプのバッファを提供します。など。ここでは、具体的な使用法を確認するために ByteBuffer を例に挙げます。

最初にネイティブ コードを見てみましょう:

int32_t fillInt8Buffer(int8_t *buf, int len, char value) {
  int i;

  for (i=0;i < len;i++) {
    buf[i] = value;
  }
  return len;
}

ここでバッファが埋められます。明らかに、このバッファは後で使用する必要があるため、ここでは、配列を使用するのは適切ではありません。ByteBuffer を使用することを選択できます:

int fillInt8Buffer(ByteBuffer buf, int len, byte value);

そして、その使用方法を確認します:

TestLibrary lib = Native.load("testlib", TestLibrary.class);

        ByteBuffer buf  = ByteBuffer.allocate(1024).order(ByteOrder.nativeOrder());
        final byte MAGIC = (byte)0xED;
        lib.fillInt8Buffer(buf, 1024, MAGIC);
        for (int i=0;i < buf.capacity();i++) {
            assertEquals("Bad value at index " + i, MAGIC, buf.get(i));
        }

変数パラメータ

ネイティブおよびJAVA 自体は、すべて可変パラメータをサポートしています。例を見てみましょう。ネイティブ メソッド内:

int32_t addVarArgs(const char *fmt, ...) {
  va_list ap;
  int32_t sum = 0;
  va_start(ap, fmt);

  while (*fmt) {
    switch (*fmt++) {
    case &#39;d&#39;:
      sum += va_arg(ap, int32_t);
      break;
    case &#39;l&#39;:
      sum += (int) va_arg(ap, int64_t);
      break;
    case &#39;s&#39;: // short (promoted to &#39;int&#39; when passed through &#39;...&#39;) 
    case &#39;c&#39;: // byte/char (promoted to &#39;int&#39; when passed through &#39;...&#39;)
      sum += (int) va_arg(ap, int);
      break;
    case &#39;f&#39;: // float (promoted to ‘double&#39; when passed through ‘...&#39;)
    case &#39;g&#39;: // double
      sum += (int) va_arg(ap, double);
      break;
    default:
      break;
    }
  }
  va_end(ap);
  return sum;
}

対応する JAVA メソッド マッピングは次のとおりです:

public int addVarArgs(String fmt, Number... args);

対応する呼び出しコードは次のとおりです:

りー

以上がJava の JNA 型マッピングの詳細と使用法への注意の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。