• JNA嵌套结构体,如何访问内嵌结构体的成员?


    如果不明白如何创建DLL动态链接库项目,可参照文章:https://blog.csdn.net/Xeon_CC/article/details/124873221

    提出问题:
    C语言程序有个结构体叫BaseGrid,里面有个Grid结构体的成员multi_grid,而且multi_grid是个二维指针数组,意思也就是说相当于java里面的Grid[][]二维数组类型。
    请问,Java怎么访问C语言内的BaseGrid内的multi_grid成员变量,即Java如何访问嵌套结构体的成员变量?

    在Java,我们会这么做:
    BaseGrid baseGrid = new BaseGrid();
    for循环,new很多个Grid对象,然后把Grid对象赋值给BaseGrid的multi_grid成员,其中multi_grid成员是装Grid对象的数组。
    baseGrid.set(xxx); //做很多的set方法设置成员。
    最后我们要访问baseGrid对象里面的multi_grid成员的某个元素Grid类的属性。
    我们这么做:
    baseGrid.getMultiGrid()[2][3].getW();
    但是,如果是Java传递BaseGrid对象给C语言,然后返回baseGrid对象,这时候返回的baseGrid对象就不能如上所说的方法去获取了。
    我们既然不能用getter方法获取,也不能用成员变量名称获取,比如obj.name,类似这种访问方式,思路是用地址偏移量的方式去访问成员。
    获取成员的方法如下:

    创建一个Maven项目,Java代码如下:

    package com.example.jna_test01;
    
    import com.sun.jna.*;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    import java.util.HashMap;
    
    @SpringBootApplication
    public class JnaTest01Application<T> {
    
        public interface CLibrary extends Library {
            JnaTest01Application.CLibrary INSTANCE = (JnaTest01Application.CLibrary) Native.load((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
    
            void printf(String format, Object... args);
        }
    
        public interface DllForJava extends Library {
            DllForJava INSTANCE = (DllForJava) Native.load("src/main/java/com/example/jna_test01/dll/JNATestDLL.dll", DllForJava.class);
    
            public int getArrSum(Pointer arr, int row, int col);
    
            public BaseGrid getBaseGrid(BaseGrid.ByReference bg_ref, int row, int col);
        }
    
        //测试多重指针
        public void testMultiPointer() {
            CLibrary.INSTANCE.printf("Hello, World\n");
            //分配一个24字节的内存,这里准备装入3个指针,一个指针占8个字节
            Pointer pointers = new Memory(24);
            int pointer_size = 8;
            int int_size = 4;
            int row = 3;
            int col = 5;
            for (int i = 0; i < row; i++) {
                //分配20字节的内存空间,并且该指针指向这个内存空间的首地址
                Pointer pointer = new Memory(20);
                for (int j = 0; j < col; j++) {
                    pointer.setInt(j * int_size, i * j * 2 + 1);
                }
                pointers.setPointer(i * pointer_size, pointer);
                //这里不要释放内存
    //            Native.free(Pointer.nativeValue(pointer));
            }
            //调用Dll动态链接库内的getArrSum函数
            System.out.println(DllForJava.INSTANCE.getArrSum(pointers, row, col));
            System.out.println("释放内存之前,pointers地址:" + pointers);
            Native.free(Pointer.nativeValue(pointers));
            Pointer.nativeValue(pointers, 0);
            System.out.println("释放内存之后,pointers地址:" + pointers);
        }
    
        //测试结构体里面有结构体成员
        public void testStructInStruct() {
            BaseGrid baseGrid = new BaseGrid();
            int row = 2;
            int col = 3;
            BaseGrid bg = DllForJava.INSTANCE.getBaseGrid(baseGrid, row, col);
            //https://blog.csdn.net/wankcn/article/details/121209323  C语言的long类型占用几个字节,看操作系统,只有64位的linux系统或者unix占8个字节
            //要注意,在c语言char* str是指针,无论你的char数组多长,只占8个字节,因为它只是一个指针
            HashMap<String, Integer> fieldMap = new HashMap<>();
            fieldMap.put("w", 0);
            fieldMap.put("d", 4);
            fieldMap.put("db", 8);
            fieldMap.put("str", 16);
            fieldMap.put("lg", 24);
            //每个Grid对象占用几个字节,32个字节,计算是28个字节,但是由于8字节对齐,所以占用32个字节
            int gridSize = 32;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    int w = bg.multi_grid.getPointerArray(0, row)[i].getInt(j * gridSize + fieldMap.get("w"));
                    int d = bg.multi_grid.getPointerArray(0, row)[i].getInt(j * gridSize + fieldMap.get("d"));
                    double db = bg.multi_grid.getPointerArray(0, row)[i].getDouble(j * gridSize + fieldMap.get("db"));
                    String str = byteArrToString(bg.multi_grid.getPointerArray(0, row)[i].getPointer(j * gridSize + fieldMap.get("str")).getByteArray(0, 20));
                    int lg = bg.multi_grid.getPointerArray(0, row)[i].getInt(j * gridSize + fieldMap.get("lg"));
                    System.out.println("w = " + w + ", d = " + d + ", db = " + db + ", " + str + ", " + "lg = " + lg);
                }
            }
        }
    
        public String byteArrToString(byte[] bytes) {
            String str = "";
            for (int i = 0; i < bytes.length; i++) {
                str += (char) bytes[i];
            }
            return str;
        }
    
        public static void main(String[] args) {
    //        SpringApplication.run(DemoApplication.class, args);
            JnaTest01Application japp = new JnaTest01Application();
            japp.testMultiPointer();
            japp.testStructInStruct();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    package com.example.jna_test01;
    
    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    
    @Structure.FieldOrder({"multi_grid", "row", "col"})
    public class BaseGrid extends Structure implements Structure.ByReference {
    
        public Pointer multi_grid;
        public int row;
        public int col;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    package com.example.jna_test01;
    
    import com.sun.jna.Structure;
    import com.sun.jna.WString;
    
    @Structure.FieldOrder({"w", "d"})
    public class Grid extends Structure implements Structure.ByReference {
        public int w;
        public int d;
        public double db;
        public WString str;
        public long lg;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    DLL动态链接库C语言代码:

    #define EXPORT __declspec(dllexport)
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    struct Grid {
    	int w;
    	int d;
    	double db;
    	char* str;
    	long lg;
    };
    
    struct BaseGrid {
    	Grid** multi_grid;
    	int row;
    	int col;
    };
    
    
    
    extern "C" {
    	
    	EXPORT int getArrSum(int** arr, int row, int col) {
    		/*真正意义上说,i和j都是地址偏移量,并不是说第几个元素,
    		arr的第一维度是指针arr[0],arr[1]....都是指针,指针占8个字节,
    		所以,arr[0]访问的是第1个字节的首地址,arr[1]访问的是第9个字节的首地址,也就是每偏移一个单位是8个字节。
    		然而,arr的第二维存的是整型,每偏移一个单位就是4个字节。
    		*/
    		int sum = 0;
    		for (int i = 0; i < row; i++) {
    			for (int j = 0; j < col; j++) {
    				
    				printf("%d\t", arr[i][j]);
    			}
    			printf("\n");
    		}
    		for (int i = 0; i < row; i++) {
    			for (int j = 0; j < col; j++) {
    				sum += arr[i][j];
    			}
    		}
    		return sum;
    	}
    
    	EXPORT BaseGrid* getBaseGrid(BaseGrid* baseGrid, int row, int col) {
    		Grid** gridArrs = new Grid * [row];
    		for (int i = 0; i < row; i++) {
    			Grid* grids = new Grid[col];
    			for (int j = 0; j < col; j++) {
    				(grids + j)->w = i * j + 3;
    				(grids + j)->d = i + j + i * j + 20;
    				(grids + j)->db = i + j + i * j + 40;
    				(grids + j)->str = new char[20]{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
    				(grids + j)->lg = 90L;
    			}
    			gridArrs[i] = grids;
    		}
    		baseGrid->multi_grid = gridArrs;
    		return baseGrid;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    执行结果
    在这里插入图片描述

  • 相关阅读:
    ARP欺骗攻击实操
    树叶识别系统python+Django网页界面+TensorFlow+算法模型+数据集+图像识别分类
    Spring Boot快速入门:构建简单的Web应用
    【快速搞定Webpack5】处理图片资源(四)
    数据中心绿色低碳重要趋势下,希捷用创新技术让磁盘“重生”
    0015Java程序设计-springboot美食网站
    中电金信:The Financial-Grade Digital Infrastructure
    循环结构——求素数个数和平均值
    手把手教你 centos 7 安装RabbitMQ
    单例模式、工厂模式 c++关键字 static
  • 原文地址:https://blog.csdn.net/Xeon_CC/article/details/124902460