Home > Java > javaTutorial > Java's JNA type mapping attention to details and usage

Java's JNA type mapping attention to details and usage

王林
Release: 2023-04-18 17:07:03
forward
1387 people have browsed it

String

The first is the mapping of String. String in JAVA actually corresponds to two native types: const char* and const wchar_t*. By default String will be converted to char*.

char is an ANSI data type, and wchar_t is a Unicode character data type, also called a wide character.

If JAVA's unicode characters are to be converted into a char array, some encoding operations need to be performed. If jna.encoding is set, the set encoding method will be used for encoding. By default, the encoding method is "UTF8".

If it is WString, Unicode values ​​can be copied directly to WString without any encoding.

Let’s look at a simple example first:

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

wchar_t* returnWStringArgument(wchar_t *arg) {
  return arg;
}
Copy after login

The above native code can be mapped to:

String returnStringArgument(String s);
WString returnWStringArgument(WString s);
Copy after login

Let’s look at a different example. If the definition of the native method is like this :

int getString(char* buffer, int bufsize);

int getUnicodeString(wchar_t* buffer, int bufsize);
Copy after login

We have defined two methods, the parameters of which are char* and wchar_t*.

Next, let’s take a look at how to define method mapping in JAVA:

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

The following is the specific use:

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

Some students may ask, since in JAVA String can be converted into char*, why do we need to use byte array here?

This is because the getString method needs to modify the contents of the incoming char array, but because String is immutable, String cannot be used directly here. We need to use a byte array.

Then we use Native.toString(byte[]) to convert the byte array into a JAVA string.

Look at another return value situation:

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

Generally, if the native method returns string directly, we can use String for mapping:

// Mapping A
String getString();
// Mapping B
WString getString();
Copy after login

If the native code After allocating memory space for String, we'd better use Pointer in JNA as the return value, so that we can release the occupied space at some point in the future, as shown below:

Pointer getString();
Copy after login

Buffers, Memory, Arrays and Pointers

When do you need to use Buffers and Memory?

Generally, if an array of basic data is passed as a parameter to a function, you can use the basic class directly in JAVA array instead. But if the native method still needs to access the array after the method returns (save the pointer to the array), in this case it is not appropriate to use the array of the base class. In this case, we need to use ByteBuffers or Memory .

We know that arrays in JAVA have lengths, but for native methods, the returned array is actually a pointer to the array, and we do not know the length of the returned array, so if the native method If an array pointer is returned, it is inappropriate to use arrays for mapping in JAVA code. In this case, you need to use Pointer.

Pointer represents a pointer. Let’s look at the example of Pointer first. The first is the native code:

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

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

The next is the JAVA mapping:

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

In addition to the basic Pointer, you can also customize the typed Pointer, which is PointerType. You only need to inherit PointerType, as shown below:

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

Look at the string again Array:

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

The corresponding JAVA mapping is as follows:

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

WString returnWideStringArrayElement(WString[] args, int which);
Copy after login

Corresponding to Buffer, JAVA NIO provides many types of buffers, such as ByteBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer, etc. . Here we take ByteBuffer as an example to see the specific usage.

First look at the native code:

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

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

The buffer is filled here. Obviously, this buffer needs to be used later, so here It is not appropriate to use an array. We can choose to use ByteBuffer:

int fillInt8Buffer(ByteBuffer buf, int len, byte value);
Copy after login

and then see how to use it:

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));
        }
Copy after login

Variable parameters

For native and JAVA itself , all support variable parameters. Let’s take an example. In the native method:

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;
}
Copy after login

The corresponding JAVA method mapping is as follows:

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

The corresponding calling code is as follows:

int arg1 = 1;
int arg2 = 2;
assertEquals("32-bit integer varargs not added correctly", arg1 + arg2,
                     lib.addVarArgs("dd", arg1, arg2));
Copy after login

The above is the detailed content of Java's JNA type mapping attention to details and usage. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:yisu.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Issues
Install JAVA
From 1970-01-01 08:00:00
0
0
0
Unable to install java
From 1970-01-01 08:00:00
0
0
0
Can java be used as the backend of the web?
From 1970-01-01 08:00:00
0
0
0
Is this in Java language?
From 1970-01-01 08:00:00
0
0
0
Help: JAVA encrypted data PHP decryption
From 1970-01-01 08:00:00
0
0
0
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template