如果不明白如何创建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{ 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, Worldn"); //分配一个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 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#include 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) { int sum = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { printf("%dt", 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; } }
执行结果



