• JNA学习笔记一:概念


    默认情况下,所有Structure对象在本机函数调用之前,都将其Java字段复制到其本机内存中,并在调用后复制回来。

    默认类型映射

    Java 原始类型(及其对象等价物)直接映射到相同大小的本机 C 类型。

    NativeTypeSizeJava TypeCommon Windows Types
    char8-bit integerbyteBYTE, TCHAR
    short16-bit integershortWORD
    wchar_t16/32-bit charactercharTCHAR
    int32-bit integerintDWORD
    intboolean valuebooleanBOOL
    long32/64-bit integerNativeLongLONG
    longlong 64-bit integerlong__int64
    float32-bit FPfloat
    double64-bit FPdouble
    char*C stringStringLPCSTR
    void*pointerPointerLPVOID, 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
    
    • 1
    • 2
    • 3
    • 4
    // 等效 JNA 映射
    void fill_buffer(int[] buf, int len);
    
    • 1
    • 2

    注意:如果参数要给函数调用范围之外的本机函数使用,则必须使用 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());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    或者,您可以使用具有所需类型的单个元素的 Java 数组,但 ByReference 更好地传达了代码的意图。除了 getByteArray() 之外,Pointer 类还提供了许多访问器方法,它们有效地用作内存上的类型转换。

    类型安全指针可以通过派生自 PointerType 类来声明。

    https://github.com/java-native-access/jna/blob/master/www/ByRefArguments.md#using-byreference-arguments

    在参考:JNI便捷开发框架JNA框架之结构参数体传递(四) 这篇文章后,实践得出ByReference传递可以修改结构体中的成员变量值,ByValue传递不可以。

    从 Java 到 Native 的自定义映射

    TypeMapper 类和相关接口提供将用作参数、返回值或结构成员的任何 Java 类型转换为或从本机类型转换。示例 Win32 API 接口使用类型映射器将 Java 布尔值转换为 Win32 BOOL 类型。 TypeMapper 实例作为传递给 Native.load 的选项映射中的 TYPE_MAPPER 键的值传递。

    或者,用户定义的类型可以实现 NativeMapped 接口,该接口确定在逐个类的基础上与本机类型之间的转换。

    您还可以自定义 Java 方法名称到相应的本机函数名称的映射。 StdCallFunctionMapper 是一种从 Java 接口方法签名自动生成 std​​call 修饰的函数名称的实现。映射器应作为传递给 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
    
    • 1
    • 2

    总结

    在参考:JNI便捷开发框架JNA框架之入门(一) 系列文章后,了解到了JNA是怎么工作的。

    1. Java接口签名和C文件(xxx.c文件)中方法签名要一直。类型之间的转换,需要注意。一般类型和Java可以简单对应,字符串类型C语言中是char* str,但是int *c这样的情况,Java中就需要使用Pointer来对应。
    2. Pointer虽然可以满足C语言中的指针类型,但是其内存管理也和C语言一样,需要我们手动维护,所以就有了ByReference类及派生类IntByReference(int)、PointerByReference(字符串)等由Java自动管理内存的类。Pointer类Reference类大体上后者更优,但是对于更多层的指针引用,可能Pointer更合适。
  • 相关阅读:
    XX集团BIM项目解决方案
    想学嵌入式开发,薪资怎么样?
    C/C++总结笔记——指针1:二级指针、空指针(NULL和nullptr)、野指针
    RENAME,CHANGE,ALTER,MODIFY 四个字段的作用和区别
    TikTok Shop订单狂涨,黑五全托管品类日卖爆了
    ProtoBuf lite版中使用Any
    smqtt:高性能开源MQTT消息代理Broker
    VUE面试题总结2
    手机云便签待办分类内容怎么排序?
    Unity DOTS系列之Aspect核心机制分析
  • 原文地址:https://blog.csdn.net/u013066244/article/details/125516710