Java's JNA type mapping attention to details and usage
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; }
The above native code can be mapped to:
String returnStringArgument(String s); WString returnWStringArgument(WString s);
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);
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);
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);
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();
Generally, if the native method returns string directly, we can use String for mapping:
// Mapping A String getString(); // Mapping B WString getString();
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();
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]; }
The next is the JAVA mapping:
Pointer returnPointerArgument(Pointer p); Pointer returnPointerArrayElement(Pointer[] args, int which);
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);
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]; }
The corresponding JAVA mapping is as follows:
String returnStringArrayElement(String[] args, int which); WString returnWideStringArrayElement(WString[] args, int which);
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; }
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);
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)); }
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 'd': sum += va_arg(ap, int32_t); break; case 'l': sum += (int) va_arg(ap, int64_t); break; case 's': // short (promoted to 'int' when passed through '...') case 'c': // byte/char (promoted to 'int' when passed through '...') sum += (int) va_arg(ap, int); break; case 'f': // float (promoted to ‘double' when passed through ‘...') case 'g': // double sum += (int) va_arg(ap, double); break; default: break; } } va_end(ap); return sum; }
The corresponding JAVA method mapping is as follows:
public int addVarArgs(String fmt, Number... args);
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));
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!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



Guide to Perfect Number in Java. Here we discuss the Definition, How to check Perfect number in Java?, examples with code implementation.

Guide to Weka in Java. Here we discuss the Introduction, how to use weka java, the type of platform, and advantages with examples.

Guide to Smith Number in Java. Here we discuss the Definition, How to check smith number in Java? example with code implementation.

In this article, we have kept the most asked Java Spring Interview Questions with their detailed answers. So that you can crack the interview.

Java 8 introduces the Stream API, providing a powerful and expressive way to process data collections. However, a common question when using Stream is: How to break or return from a forEach operation? Traditional loops allow for early interruption or return, but Stream's forEach method does not directly support this method. This article will explain the reasons and explore alternative methods for implementing premature termination in Stream processing systems. Further reading: Java Stream API improvements Understand Stream forEach The forEach method is a terminal operation that performs one operation on each element in the Stream. Its design intention is

Guide to TimeStamp to Date in Java. Here we also discuss the introduction and how to convert timestamp to date in java along with examples.

Capsules are three-dimensional geometric figures, composed of a cylinder and a hemisphere at both ends. The volume of the capsule can be calculated by adding the volume of the cylinder and the volume of the hemisphere at both ends. This tutorial will discuss how to calculate the volume of a given capsule in Java using different methods. Capsule volume formula The formula for capsule volume is as follows: Capsule volume = Cylindrical volume Volume Two hemisphere volume in, r: The radius of the hemisphere. h: The height of the cylinder (excluding the hemisphere). Example 1 enter Radius = 5 units Height = 10 units Output Volume = 1570.8 cubic units explain Calculate volume using formula: Volume = π × r2 × h (4

Java is a popular programming language that can be learned by both beginners and experienced developers. This tutorial starts with basic concepts and progresses through advanced topics. After installing the Java Development Kit, you can practice programming by creating a simple "Hello, World!" program. After you understand the code, use the command prompt to compile and run the program, and "Hello, World!" will be output on the console. Learning Java starts your programming journey, and as your mastery deepens, you can create more complex applications.
