代码之家  ›  专栏  ›  技术社区  ›  Gio

当sizeof(long)为4时,为什么需要为JNA指针预留超过4个字节来接收long?

  •  0
  • Gio  · 技术社区  · 8 年前

    我正在使用JNA与用Visual Studio 2015编译的本机C库通信。我在一台64位的机器上工作。我试图通过一个长指针接收C函数的值 long *pdays 参数。我有以下例外:

    java.lang.indexoutofboundsException:边界超过可用空间: 大小=4,偏移量=8。 在COM.Sun.jn.Mealth.GETHOLN(内存. Java:498)

    我不明白这里遗漏了什么,如果我只为指针保留4个字节的内存,这会导致上面的崩溃,但是如果我保留8个,一切都会好起来。但是sizeof(long)返回4,那么为什么我需要保留超过4个字节?

        System.out.println(NativeLong.SIZE); // --> 4
        System.out.println(Native.LONG_SIZE); // --> 4
    
        // Pointer pDays = new Memory(Native.LONG_SIZE); Results in IndexOutOfBoundsException
        Pointer pDays = new Memory(8); // 
    
        nativeLib.GetDaysUntilExpiration(pDays);
        return pDays.getLong(0); // crashes here when reserving just 4 bytes
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Daniel Widdis    8 年前

    它崩溃是因为您试图从只分配了4个字节的本机内存中读取8个字节。

    不管本机类型是什么,或者它只有4个字节。这个 Memory 只需保存4个字节,您可以以任何方式进行解释。你可以得到一个 byte[] 数组,或 int (4个字节)或者甚至是 short byte 只读取该字节数。你甚至可以试试 String (虽然没有空终止符,但您可能会读到超过允许的4个字节的内容,谁知道您会得到什么,这样做很危险。)

    你要求得到一个Java long 这是一个8字节的变量;因此,代码检查偏移量中接下来的8个字节是否适合分配的内存。代码来自 Memory.java 是否硬编码:

    boundsCheck(offset, 8);
    

    JavaDoc很清楚这是为什么:

    将本机指针间接指向 malloc 空间,洛杉矶 Pointer.getLong . 但此方法执行边界检查以确保 间接寻址不会导致内存超出 马洛克 ED空间 已访问。

    正确的方法是,在不手动分配空间的情况下,只需使用 NativeLongByReference . JNA将自己负责空间的分配和值的检索,您不必担心本机大小。

    NativeLongByReference pDays = new NativeLongByReference();
    nativeLib.GetDaysUntilExpiration(pDays);
    return pDays.getValue().longValue(); 
    

    编辑:我注意到在您的注释中,您说“C函数参数是指针,使用NativeLongByReference将导致“LongByReference无法转换为指针”--这不是C函数的问题,而是接口中的JNA映射的问题。最好更改的JNA映射 GetDaysUntilExpiration 接受 本地引用 参数。如果不能更改该函数的JNA映射,可以使用 pDays.getPointer() 作为论据。