JNA类型映射实例__结构体中包含字符串数组

本文介绍了一个C语言中的结构体如何被Java通过JNA技术进行映射,并实现了跨语言的数据传递。具体展示了结构体定义、函数声明及Java端的调用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处,http://blog.youkuaiyun.com/rainteen

作者邮箱:rainteen@163.com


C代码中结构体定义:

typedef struct STRU_FILE_STRU
{
	char* keyStoreFile[2];
	char* keyFile[2];
}KEYSTORE_FILE_STRU;
C代码中使用此结构体的函数声明:

extern "C" __declspec(dllexport) int __stdcall writeStruct(KEYSTORE_FILE_STRU* fileStruct);
C代码中对应声明的函数声明:
int _stdcall writeStruct(KEYSTORE_FILE_STRU* fileStruct)
{
	try{
		char* keystoreFile01="D:/testOK/keystoreFile01";
		int len = ::strlen(keystoreFile01);
		::memcpy(fileStruct->keyStoreFile[0], keystoreFile01, len);

		char* keystoreFile02="D:/testOK/keystoreFile02";
		len = ::strlen(keystoreFile02);
		::memcpy(fileStruct->keyStoreFile[1], keystoreFile02, len);

		char* keyFile01="D:/testOK/keyFile01";
		len = ::strlen(keyFile01);
		::memcpy(fileStruct->keyFile[0], keyFile01, len);

		char* keyFile02="D:/testOK/keyFile02";
		len=::strlen(keyFile02);
		::memcpy(fileStruct->keyFile[1], keyFile02, len);
	}catch(char *){
		return 0;
	}
	return 1;
}


JNA映射到 Java中的结构体:

package rainteen.jnadll;

import java.util.Arrays;
import java.util.List;

import rainteen.ByteArray;

import com.sun.jna.Pointer;
import com.sun.jna.Structure;

public class KEYSTORE_FILE_STRU extends Structure {
	public ByteArray.ByReference[] keyStoreFile = new ByteArray.ByReference[2];
	public ByteArray.ByReference[] keyFile = new ByteArray.ByReference[2];

	public KEYSTORE_FILE_STRU() {
		this.setAlignType(Structure.ALIGN_DEFAULT);
		this.keyStoreFile[0] = new ByteArray.ByReference();
		this.keyStoreFile[1] = new ByteArray.ByReference();
		this.keyFile[0] = new ByteArray.ByReference();
		this.keyFile[1] = new ByteArray.ByReference();
	}

	public KEYSTORE_FILE_STRU(Pointer pointer) {
		this.setAlignType(Structure.ALIGN_DEFAULT);
		this.keyStoreFile[0] = new ByteArray.ByReference();
		this.keyStoreFile[1] = new ByteArray.ByReference();
		this.keyFile[0] = new ByteArray.ByReference();
		this.keyFile[1] = new ByteArray.ByReference();
	}

	public static class ByReference extends KEYSTORE_FILE_STRU implements
			Structure.ByReference {
	}

	public static class ByValue extends KEYSTORE_FILE_STRU implements
			Structure.ByValue {
	}

	@SuppressWarnings("unchecked")
	protected List getFieldOrder() {
		return Arrays.asList(new String[] { "keyStoreFile", "keyFile" });
	}
}

其中的字节数组自定义结构体JNA定义如下:

package rainteen;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Pointer;
import com.sun.jna.Structure;

public class ByteArray extends Structure {
	public static final int MAX_LENGTH = 512;

	public byte[] data = new byte[MAX_LENGTH];

	public static class ByReference extends ByteArray implements
			Structure.ByReference {
	}

	public static class ByValue extends ByteArray implements Structure.ByValue {
	}

	public ByteArray() {
		super();
		this.setAlignType(Structure.ALIGN_DEFAULT);
	}

	public ByteArray(Pointer pointer) {
		super(pointer);
		this.setAlignType(Structure.ALIGN_DEFAULT);
	}

	public void init(byte[] data) {
		if (data != null) {
			int minLen = (data.length > MAX_LENGTH) ? MAX_LENGTH : data.length;
			System.arraycopy(data, 0, this.data, 0, minLen);
		}
	}

	public byte[] getData() {
		return this.data;
	}

	@SuppressWarnings("unchecked")
	protected List getFieldOrder() {
		return Arrays.asList(new String[] { "data" });
	}
}


Java中调用C函数的方法示例:

	@Test
	public void testWriteStruct() {
		KEYSTORE_FILE_STRU.ByReference fileStruct = new KEYSTORE_FILE_STRU.ByReference();

		int res = this.jnaDll.writeStruct(fileStruct);
		fileStruct.autoRead();
		byte[] data0 = fileStruct.keyStoreFile[0].getData();
		System.out.println(TypeUtil.toString(data0));
		byte[] data1 = fileStruct.keyStoreFile[1].getData();
		System.out.println(TypeUtil.toString(data1));

		byte[] key0 = fileStruct.keyFile[0].getData();
		System.out.println(TypeUtil.toString(key0));
		byte[] key1 = fileStruct.keyFile[1].getData();
		System.out.println(TypeUtil.toString(key1));

		Assert.assertTrue(res == 1);
	}



### 使用 JNA 调用包含结构体数组的本地函数 当通过 JNA 调用包含结构体数组的本地函数时,可以利用 `Structure` 类来表示 C 结构体,并将其映射Java 中的对象。如果目标函数需要一个连续分配在内存中的结构体数组,则可以直接使用 `Structure.toArray()` 方法创建这样的数组。 以下是实现此功能的关键点: #### 映射 C 结构体Java C 结构体可以通过继承 `com.sun.jna.Structure` 来映射Java 对象。例如,假设有一个简单的 C 结构体如下所示: ```c typedef struct { int id; char name[10]; } MyStruct; ``` 对应的 Java 实现可能如下: ```java public class MyStruct extends Structure { public int id; public byte[] name = new byte[10]; @Override protected List<String> getFieldOrder() { return Arrays.asList("id", "name"); } } ``` 这里需要注意的是,字段顺序必须与 C 定义一致,并且字符串通常需要用字节数组代替[^1]。 #### 创建并初始化结构体数组 对于某些情况,可能不需要手动初始化整个数组,因为底层库会负责分配和设置这些值。然而,在其他情况下,您确实需要预先填充数据。此时可借助 `Structure.toArray(int)` 方法生成所需的实例列表。下面是一个例子展示如何操作: ```java MyStruct myStructInstance = new MyStruct(); myStructInstance.id = 42; // 设置初始 ID 值 System.arraycopy("Test".getBytes(), 0, myStructInstance.name, 0, Math.min(myStructInstance.name.length, "Test".length())); // 创建大小为 N 的结构体数组 List<MyStruct> structsAsList = Collections.nCopies(N, null); for (int i=0;i<N;i++) { structsAsList.set(i,new MyStruct()); } Object[] rawArray = myStructInstance.toArray(structsAsList.size()); // 将其转换成实际参数形式传递给 Native 函数 Pointer pointerToNativeMemoryBlockForStructures = ((MyStruct[])rawArray)[0].getPointer(); ``` 上述代码片段展示了如何构建一个已初始化的大规模结构体数组,并准备供本地方法使用的指针[^1]。 #### 调用带有结构体数组作为输入/输出参数的本机函数 最后一步就是定义接口并通过它访问外部共享对象上的适当符号名。假设有这样一个 C 函数签名接受我们的结构体数组: ```c void process_struct_array(MyStruct* array, size_t count); ``` 那么相应的 Java 接口可能是这样写的: ```java import com.sun.jna.Library; import com.sun.jna.Native; public interface CLibrary extends Library { CLibrary INSTANCE = Native.load("your_native_library_name", CLibrary.class); void process_struct_array(MyStruct.ByReference[] array, long count); } ``` 注意这里的 `ByReference` 是为了确保传入的是指向第一个元素而非副本的数据引用[^1]。 一旦完成了以上准备工作之后就可以轻松地调用了: ```java CLibrary.INSTANCE.process_struct_array((MyStruct.ByReference[])rawArray, N); ``` ### 总结 综上所述,要成功运用 JNA 处理大型结构体数组的情况,主要分为三个阶段:一是正确定义好对应关系;二是合理安排资源管理流程包括但不限于显式释放不再使用的句柄或者缓冲区等内容;三是正确书写跨平台兼容性强的应用逻辑从而达到预期效果[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值