【问题标题】:Java JNA Linkedlist declarationJava JNA 链表声明
【发布时间】:2020-10-10 08:53:52
【问题描述】:

我需要从 Java 应用程序访问本机 C++ 代码 .dll。本机 int 函数效果很好,但是对于 Linkedlist Struct 我在 Internet 上找不到任何关于如何声明 java 接口的参考

这个 C++ 代码

struct usb_relay_device_info
{
    unsigned char *serial_number;
    char *device_path;
    usb_relay_device_type type;
    usb_relay_device_info* next;
};

int EXPORT_API usb_relay_init(void);
struct usb_relay_device_info EXPORT_API * usb_relay_device_enumerate(void);
int EXPORT_API  usb_relay_device_open(struct usb_relay_device_info* device_info);

这是java部分

public interface JNI extends Library {
JNI INSTANCE = (JNI) Native.loadLibrary("usb", JNI.class);

public static class usb_relay_device_info extends Structure {
    public static class DeviceInfo extends usb_relay_device_info implements Structure.ByValue {
    }

    public byte[] serial_number = new byte[1024];
    public String device_path;
    public int type;
}


int usb_relay_init();
usb_relay_device_info.DeviceInfo usb_relay_device_enumerate();
int usb_relay_device_open(usb_relay_device_info.DeviceInfo deviceInfo);

}

我已经在 java 代码中创建了结构(不是 Linkedlist 结构)。因此,当我调用该函数时,值没有显示出来,因为它应该是一个列表(C++ 中的链表)

【问题讨论】:

  • 为什么结构中有四个元素,而你的映射中只有三个?你漏掉了nextchar *serial_number 和其他 args 也意味着指向本机映射内存区域的指针,而不是固定宽度的字节数组。 1024 是从哪里来的?
  • 是的还是不见了,因为c++中下一个变量是linkedlist,Java中如何声明呢?我从其他网站读到参考资料,c++ 中的 unsigned char 是 Java 中的字节数组。好的,serial_number 应该更改为 String 更好吗? 1024只是随机猜测哈哈。
  • 随机猜测在编程中很少有帮助。 :)。找出 API 是如何描述该字段的,char * 很可能是一个以 null 结尾的字符串,因此在 Java 中是一个 String
  • 对于 Next 字段,Pointer 将始终有效,但需要手动处理指针以迭代链表。 usb_relay_device_info.ByReference 会是更好的选择。

标签: java c++ struct linked-list jna


【解决方案1】:

您说“我在 Internet 上找不到任何关于如何声明 java 接口的参考资料”,但有很多参考资料,包括 JNA 的 Overview,链接到主项目页面。

你会发现char *是一个C字符串,应该映射到Java的String

usb_relay_device_type 映射必须在您正在映射的 API 中引用。在这种情况下,它是一个enum 类型,它是一个整数,所以int 在这里可能是合适的。 (在某些情况下,它可以是较小的整数值,例如 shortbyte,但这种情况很少见。)

至于指向下一个设备的指针,在概览页面struct* 下也有引用。该链接(或明确)链接到Structure.ByReference。这可能并不明显,但也链接在 JNA 项目主页面上的 JNA FAQ 放大了。如果还不清楚,这里总结一下:

  • 默认情况下,作为结构内的字段列出的结构被视为“按值”,即完整的结构及其字段插入行中。要获得这种行为,您只需声明结构名称即可。
  • 如果您想要相反的行为(通过引用),那么您必须明确声明,JNA 会将指针映射到其他地方的结构。这是你的情况,正确的结构映射是usb_relay_device_info.ByReference。 (您还需要更改结构声明以实现 ByReference - 上面链接的 JNA 概述有一个示例。)
  • 在函数参数中使用时,例如usb_relay_device_open(),情况正好相反:“按引用”是默认值,如果相关,您只需明确指定“按值”即可。在这种情况下,它不是 - 本机声明包含指针: (usb_relay_device_info*) 所以您需要 ByReference 行为。您可以将usb_relay_device_info device_info 放在那里,ByReference 将是隐式的。或者,如果您愿意(不需要),您可以使用 usb_relay_device_info.ByReference device_info,这只是多余的。

所以总的来说你的结构映射应该是:

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

    public String serial_number;
    public String device_path;
    public int type;
    public usb_relay_device_info.ByReference next;
};

您需要添加 FieldOrder,最好使用注释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-08
    • 2013-05-14
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多