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();
    }

}

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;
}

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;
}

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;
	}
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值