当前位置:网站首页>JNA学习笔记一:概念
JNA学习笔记一:概念
2022-07-07 11:00:00 【山鬼谣me】
默认情况下,所有Structure
对象在本机函数调用之前,都将其Java字段复制到其本机内存中,并在调用后复制回来。
默认类型映射
Java 原始类型(及其对象等价物)直接映射到相同大小的本机 C 类型。
Native | TypeSize | Java Type | Common Windows Types |
---|---|---|---|
char | 8-bit integer | byte | BYTE, TCHAR |
short | 16-bit integer | short | WORD |
wchar_t | 16/32-bit character | char | TCHAR |
int | 32-bit integer | int | DWORD |
int | boolean value | boolean | BOOL |
long | 32/64-bit integer | NativeLong | LONG |
long | long 64-bit integer | long | __int64 |
float | 32-bit FP | float | |
double | 64-bit FP | double | |
char* | C string | String | LPCSTR |
void* | pointer | Pointer | LPVOID, HANDLE, LPXXX |
无符号类型使用与有符号类型相同的映射。 C 枚举通常可以与“int”互换。
使用指针和数组
原始数组参数(包括结构)由它们对应的 Java 类型表示。例如:
// 原始 C 声明
void fill_buffer(int *buf, int len);
//Java的写法
void fill_buffer(int buf[], int len); // same thing with array syntax
// 等效 JNA 映射
void fill_buffer(int[] buf, int len);
注意:如果参数要给函数调用范围之外的本机函数使用,则必须使用 Memory 或 NIO 直接缓冲区。 Java 原始数组提供的内存仅在函数调用期间由本机代码使用有效。
C 字符串数组(例如 char* argv[] 到 C main),在 Java 代码中可以用 String[] 表示。 JNA 将自动传递具有 NULL 最终元素的等效数组。
使用Structures 和 Unions
当函数需要指向struct
的指针时,应使用Java的Structure
,如果struct
是按值传递会返回的,则只需对参数或返回类型类声明稍作修改即可。
通常,我们需要自己定义Structure
的派生的公共静态类。即:static class AttachOptions extends Structure
类似这样。
这允许结构共享为库接口定义的任何选项(如自定义类型映射)。您必须在 FieldOrder 注释或 getFieldOrder() 方法返回的列表中按顺序包含每个声明的字段名称。
如果函数需要结构数组(在内存中连续分配),则可以使用 Java Structure[]。传入一个 Structure 数组时,不需要初始化数组元素(函数调用会为你分配、归零内存,并为你分配元素)。如果确实需要初始化数组,则应使用 Structure.toArray 方法获取内存中连续的 Structure 元素数组,然后可以根据需要对其进行初始化。
Unions通常可以与结构互换,但要求您使用 setType 方法指示哪个Unions字段处于活动状态,然后才能将其正确传递给函数调用。
https://github.com/java-native-access/jna/blob/master/www/StructuresAndUnions.md
使用 ByReference 参数
当函数接受指向类型参数的指针时,您可以使用其中一种 ByReference 类型来捕获返回值,或子类化您自己的值。例如:
// 原始 C 声明
void allocate_buffer(char **bufp, int* lenp);
// 等效 JNA 映射
void allocate_buffer(PointerByReference bufp, IntByReference lenp);
// 用法
PointerByReference pref = new PointerByReference();
IntByReference iref = new IntByReference();
lib.allocate_buffer(pref, iref);
Pointer p = pref.getValue();
byte[] buffer = p.getByteArray(0, iref.getValue());
或者,您可以使用具有所需类型的单个元素的 Java 数组,但 ByReference 更好地传达了代码的意图。除了 getByteArray()
之外,Pointer
类还提供了许多访问器方法,它们有效地用作内存上的类型转换。
类型安全指针可以通过派生自 PointerType 类来声明。
在参考:JNI便捷开发框架JNA框架之结构参数体传递(四) 这篇文章后,实践得出ByReference传递可以修改结构体中的成员变量值,ByValue传递不可以。
从 Java 到 Native 的自定义映射
TypeMapper
类和相关接口提供将用作参数、返回值或结构成员的任何 Java 类型转换为或从本机类型转换。示例 Win32 API 接口使用类型映射器将 Java 布尔值转换为 Win32 BOOL 类型。 TypeMapper 实例作为传递给 Native.load 的选项映射中的 TYPE_MAPPER 键的值传递。
或者,用户定义的类型可以实现 NativeMapped
接口,该接口确定在逐个类的基础上与本机类型之间的转换。
您还可以自定义 Java 方法名称到相应的本机函数名称的映射。 StdCallFunctionMapper 是一种从 Java 接口方法签名自动生成 stdcall 修饰的函数名称的实现。映射器应作为传递给 Native.load 调用的选项映射中的 OPTION_FUNCTION_MAPPER 键的值传递。
https://github.com/java-native-access/jna/blob/master/www/CustomMappings.md
涉及C语言的知识
一、普通变量和的本质区别
在说到普通变量和指针变量的区别时,我更喜欢从一个更高的视角去看待这两者。首先来说,这两者都是变量,既然是变量,就会包含地址和值这两部分,例如int a , 用&a获得该变量的地址,用a获得该变量的值;普通变量和指针变量的区别就是,这两种变量的值的所表示的意义不同, 一般来说,普通变量的值,只是供程序员所使用的值,而指针变量的值则不同,它的值存放的是其他变量的地址。既然普通变量和指针变量是有所区别的,那么声明一个指针变量就必须与普通变量有所区别,c语言用int* b 声明变量b是一个指针变量,即变量b的值是可以解析成另一个变量的地址的。
int a=3;
int* b=&a;
变量a的值a是3,地址&a假设是00E1FEA0;
变量b的值b就是变量a的地址00E1FEA0,&b表示b的地址,一般来说不怎么关心,b表示获得地址为b(要清楚,这个是变量a的地址)的变量所对应的值,也就是说b=3;
将C语言文件打包成共享库文件命令
# 注意最后两个参数 libhello.so(自己的指定名称) hello.c(c文件)
gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o libhello.so hello.c
总结
在参考:JNI便捷开发框架JNA框架之入门(一) 系列文章后,了解到了JNA是怎么工作的。
- Java接口签名和C文件(xxx.c文件)中方法签名要一直。类型之间的转换,需要注意。一般类型和Java可以简单对应,字符串类型C语言中是
char* str
,但是int *c
这样的情况,Java中就需要使用Pointer
来对应。 Pointer
虽然可以满足C语言中的指针类型,但是其内存管理也和C语言一样,需要我们手动维护,所以就有了ByReference类
及派生类IntByReference(int)、PointerByReference(字符串)
等由Java自动管理内存的类。Pointer类
与Reference类
大体上后者更优,但是对于更多层的指针引用,可能Pointer
更合适。
边栏推荐
- ACL 2022 | small sample ner of sequence annotation: dual tower Bert model integrating tag semantics
- Lingyunguang of Dachen and Xiaomi investment is listed: the market value is 15.3 billion, and the machine is implanted into the eyes and brain
- Day-15 common APIs and exception mechanisms
- Shortcut key of Bash
- What are the benefits of ip2long?
- What kind of methods or functions can you view the laravel version of a project?
- The URL modes supported by ThinkPHP include four common modes, pathinfo, rewrite and compatibility modes
- 2022 practice questions and mock examination of the third batch of Guangdong Provincial Safety Officer a certificate (main person in charge)
- ICLR 2022 | pre training language model based on anti self attention mechanism
- MySQL importing SQL files and common commands
猜你喜欢
Analysis of DHCP dynamic host setting protocol
. Net ultimate productivity of efcore sub table sub database fully automated migration codefirst
Practical example of propeller easydl: automatic scratch recognition of industrial parts
Day-19 IO stream
NPM instal reports agent or network problems
基于NeRF的三维内容生成
详细介绍六种开源协议(程序员须知)
Day22 deadlock, thread communication, singleton mode
Leetcode question brushing: binary tree 26 (insertion operation in binary search tree)
ICLR 2022 | 基于对抗自注意力机制的预训练语言模型
随机推荐
[binary tree] delete points to form a forest
Analysis of DHCP dynamic host setting protocol
Day-14 common APIs
Day21 multithreading
xshell评估期已过怎么办
ICLR 2022 | pre training language model based on anti self attention mechanism
企业级自定义表单引擎解决方案(十二)--体验代码目录结构
[疑难杂症]pip运行突然出现ModuleNotFoundError: No module named ‘pip‘
Cmu15445 (fall 2019) project 2 - hash table details
Talk about four cluster schemes of redis cache, and their advantages and disadvantages
非分区表转换成分区表以及注意事项
HZOJ #236. Recursive implementation of combinatorial enumeration
用mysql查询某字段是否有索引
【无标题】
免费手机号码归属地API查询接口
- Oui. Migration entièrement automatisée de la Sous - base de données des tableaux d'effets sous net
ISPRS2021/遥感影像云检测:一种地理信息驱动的方法和一种新的大规模遥感云/雪检测数据集
Leetcode brush question: binary tree 24 (the nearest common ancestor of binary tree)
Master formula. (used to calculate the time complexity of recursion.)
Adopt a cow to sprint A shares: it plans to raise 1.85 billion yuan, and Xu Xiaobo holds nearly 40%