zoukankan      html  css  js  c++  java
  • JNA 相关问题

    JNA 相关问题

    结构体对齐问题

    要注意调用的c库字段对齐方式的相关设置。

    #pragma  pack (push,1)
    
    #pragma pack(pop)
    

    jna中提供了4种对齐方式:

        /** Use the platform default alignment. */
        public static final int ALIGN_DEFAULT = 0;
        /** No alignment, place all fields on nearest 1-byte boundary */
        public static final int ALIGN_NONE = 1;
        /** validated for 32-bit x86 linux/gcc; align field size, max 4 bytes */
        public static final int ALIGN_GNUC = 2;
        /** validated for w32/msvc; align on field size */
        public static final int ALIGN_MSVC = 3;
    

    需要在相应的结构体构造函数中加入super(ALIGN_NONE);设置对应的对齐方式。

    unsigned类型处理

    java中没有对应的无符号类型,需要进行相应的转换,以byte类型为例(c中的 unsigned char)

    public class Util {
        public static byte sendUnsignedByte(int input){
            return (byte) (input & 0xFF);
        }
    
        public static int receiveUnsignedByte(byte input){
            return input & 0xFF;
        }
    }
    

    char*

    const char* 作为函数参数,可以直接用字符串String传值。

    char** 函数回传字符串。用PointerByReference

    char** 发送数据到struct的char**类型的字段中:new StringArray(String[] strings);

    获取struct中的char**类型回传的数据: String[] getStringArray(long offset, int length)

    final PointerByReference ptrRef = new PointerByReference();
    final Pointer p = ptrRef.getValue();
    final String val = p.getString(0);
    

    获取数据,内存由c分配,那么需要c同时提供jni接口释放获取到的内存。

    发送数据:

            String strInfo = "very nice";
            byte[] bInfo = strInfo.getBytes();
            Memory info = new Memory(bInfo.length + 1);
            info.clear();
            info.write(0,bInfo,0,bInfo.length);
            info.setByte(bInfo.length,(byte)0);
            p.info = info;
    

    struct 数组

    获取数据,要调用c的接口释放分配的内存

    传递数组到c:

    关键方法:public Structure[] toArray(int size)用于在java中分配内存,和把c中获取的内存空间转化为Structure数组.

    callback

    typedef void(*callback)(PERSON*);
    
        public static class ShowCallBack implements Callback{
            public void invoke(Person.ByReference person){
                String name = "";
                byte[] data = person.name;
                int count = data.length;
                for(int i=data.length - 1;i>= 0;i--){
                    if(data[i] != 0) {
                        break;
                    }
                    count--;
                }
                if(count > 0) {
                    byte[] copy = new byte[count];
                    System.arraycopy(data,0,copy,0,count);
                    name = new String(copy);
                }
                System.out.println("callback name	"+name);
            }
        }
    

    用byte[]数组值给char[]

    由于c中字符串以结尾,因此需要在末尾多分配一个字节的空间,并把这个末尾字节设置为0

            byte[] bInfo = strInfo.getBytes();
            Memory info = new Memory(bInfo.length + 1);
            info.write(0,bInfo,0,bInfo.length);
            info.setByte(bInfo.length,(byte)0);
    

    jvm异常退出

    JNA也提供了一种保护机制。比如防止JNA出现异常不会导致JVM异常退出,默认是开启这个功能的,开启方式为 System.setProperty("jna.protected","true"); 记得要在JNA加载库文件之前调用,然后try {...} catch(Throwable e)异常,出现”非法内存访问”的时候依然会导致jvm退出。

    函数调用约定

    _stdcall和_cdecl函数调用约定 参考链接

    _cdecl,是C语言缺省的调用约定,参数采用从右到左的压栈方式,函数本身不清理堆栈,调用者负责清理堆栈。对于这种库,只要直接继承Library。

    _stdcall,是Pascal程序的缺省调用方式,WIN32 Api都采用_stdcall调用方式。参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。这种需要继承StdCallLibrary。

    如果用cpp实现库,需要调用的函数申明添加extern "C"

    #pragma  pack(push,1) //紧凑型对齐
    #ifdef __cplusplus
    extern "C" {
    #endif
    typedef void(*callback)(PERSON*);
    void show(PERSON* person,const callback cb);
    // ...更多的方法
    #ifdef __cplusplus
    }
    #endif
    #pragma pack(pop)
    

    柔性数组成员(flexible array member)

    struct blob {
        size_t length;
        unsigned char data[];
    };
    
    class Blob extends Structure {
        int length;
        byte[] data = new byte[1];
        public blob(int length) {
            this.length = length;
            this.data = new byte[length];
            allocateMemory();
        }
        public blob(Pointer p) {
            super(p);
            this.length = p.readInt(0);
            this.data = new byte[this.length];
            read();
        }
    }
    

    Strucure内存大小在java中有改动后需要及时调用allocateMemory()重新分配内存. write()方法把Strucure对象的改动及时写入到本地内存中,read()重新把本地内存中的数据读取到Strucure对象。

    参考文件

    官方文档

    用例文档

  • 相关阅读:
    postman调试参数格式
    Dapper.Contrib.Extensions扩展
    kafka dashborad 安装流程(kafka_exporter + prometheus + grafana)
    Kafka学习入门(windows环境下)
    Windows环境下载安装Kafka
    Windows环境下Zookeeper的安装及启动
    hdu4087(概率dp)
    poj3162(树形dp+线段树)
    Gym
    牛客小白月赛13 小A的柱状图(单调栈)
  • 原文地址:https://www.cnblogs.com/andyhe/p/10918822.html
Copyright © 2011-2022 走看看