java - 当 sizeof(long) 为 4 时,为什么我需要为 JNA 指针保留超过 4 个字节才能接收 long?
问题描述
我正在使用 JNA 与使用 Visual Studio 2015 编译的本机 C 库进行通信。我正在使用 64 位机器。我试图通过长指针long *pdays
参数接收 C 函数的值。我收到以下异常:
java.lang.IndexOutOfBoundsException:边界超出可用空间:com.sun.jna.Memory.boundsCheck(Memory.java:220) 处的大小 = 4,偏移量 = 8,位于 com.sun.jna.Memory.getLong(Memory.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
解决方案
It crashes because you are trying to read 8 bytes from native memory which has allocated only 4 bytes.
It doesn't matter what the native type is, or that it's only 4 bytes. The Memory
is simply holding 4 bytes that you could interpret in any fashion you wished. You could get a byte[]
array, or an int
(with those 4 bytes) or even a short
or byte
reading only that number of bytes. You could even try a String
(although without a null terminator, you'd probably read much more than the 4 bytes allowed, and who knows what you would get, so that would be dangerous.)
You have asked to get a Java long
which is an 8-byte variable; accordingly, the code checks to see whether the next 8 bytes from your offset fit inside the allocated memory. The code from Memory.java
has this hardcoded:
boundsCheck(offset, 8);
The javadoc is clear about why this is:
Indirect the native pointer to
malloc
space, a laPointer.getLong
. But this method performs a bounds checks to ensure that the indirection does not cause memory outside themalloc
ed space to be accessed.
The correct way to do what you're doing, where you don't manually allocate the space, is to simply use a NativeLongByReference
. JNA will take care of the allocation of space and retrieval of the value on its own, and you won't have to worry about the native size.
NativeLongByReference pDays = new NativeLongByReference();
nativeLib.GetDaysUntilExpiration(pDays);
return pDays.getValue().longValue();
EDIT: I note in your comment you say "The C function argument is a pointer, using a NativeLongByReference would result in a "LongByReference cannot be converted to Pointer" -- this is not an issue with the C function, but with the JNA mapping in your interface. Better to change the JNA mapping of GetDaysUntilExpiration
to take a NativeLongByReference
argument. If you can't change the JNA mapping of that function, you could work around it by using pDays.getPointer()
as the argument.
推荐阅读
- android - avc: 拒绝 { 读取 } 片段 Android
- java - 如何读取 Spring Boot 控制台输出
- java - Maven 构建 pom 失败
- elasticsearch - 有没有办法在 ElasticSearch 中使用非文本字段来进行文档相似性,例如日期或整数?
- compiler-construction - 为这个语法构造一个预测解析器表:E:=EE+/EE-/num
- reactjs - ReactJs 减去平衡项目的两个输入
- javascript - 单击时将类添加到侧边栏父菜单和子菜单
- python-3.x - 仅在图像/视频帧的某些区域检查边界框的可用性
- python - 使用 AWS Sagemaker Notebook 的生命周期配置升级 ML 库的问题
- android - Ionic AppRate 显示另一个弹出窗口