英文:
Pass pointer or PointerByReference in JNA for pointer argument in C
问题
在C++中,我有以下的头文件:
/** 默认构造函数 */
CLPLIB_EXPORT Clp_Simplex *CLP_LINKAGE Clp_newModel(void);
/** 析构函数 */
CLPLIB_EXPORT void CLP_LINKAGE Clp_deleteModel(Clp_Simplex *model);
尝试使用JNA导入这些内容,我假设我必须这样指定它们:
public static native PointerByReference Clp_newModel();
public static native void Clp_deleteModel(Pointer pModel);
这样正确吗,还是应该是 `Clp_deleteModel(PointerByReference pModel)`?奇怪的是,这两种方式在一个非常简单的测试中都能正常工作,尽管我更倾向于第一种。我猜想JNA使用了一些魔法。
// 选项1
PointerByReference a = Clp_newModel();
在模型中改变一些东西(a,2);
Clp_deleteModel(a.getPointer());
在模型中改变一些东西(a,2); // JVM在这里报告“非法内存访问”
// 选项2
PointerByReference a = Clp_newModel();
在模型中改变一些东西(a,2);
Clp_deleteModel(a); // 在这里传递了PointerByReference!
在模型中改变一些东西(a,2); // JVM在这里报告“非法内存访问”
英文:
In C++ I have the following header file:
/** Default constructor */
CLPLIB_EXPORT Clp_Simplex *CLP_LINKAGE Clp_newModel(void);
/** Destructor */
CLPLIB_EXPORT void CLP_LINKAGE Clp_deleteModel(Clp_Simplex *model);
Trying to import this with JNA, I assume that I have to specify them as such:
public static native PointerByReference Clp_newModel();
public static native void Clp_deleteModel(Pointer pModel);
Is this correct, of should it be Clp_deleteModel(PointerByReference pModel)
? Strangely, both seem to work in a very simple test, though the former does make more sense to me. I assume that JNA does some of its magic.
// option 1
PointerByReference a = Clp_newModel();
ChangeSomthingIntheModel(a,2);
Clp_deleteModel(a.getPointer());
ChangeSomthingIntheModel(a,2); // the JVM signals "illegal memory access here
// option 2
PointerByReference a = Clp_newModel();
ChangeSomthingIntheModel(a,2);
Clp_deleteModel(a); // passing the PointerByReference here!
ChangeSomthingIntheModel(a,2); // the JVM signals "illegal memory access here
答案1
得分: 2
查看CLP文档,似乎在这个简化的示例中,Pointer
或PointerByReference
都可以使用。
JNA中有三种一般的指针表示方式:
Pointer
类,它有几种方法用于从指向的本地内存中读取和写入。PointerType
类,可以扩展它以表示一个没有其他功能的指针,如果您不需要Pointer
功能,则更好。- 一系列的
<something>ByReference
类,它们是指向特定类型对象的指针。
因为您所做的一切都是操作指针值,所以这些都可以工作:更重要的是,您传递一个与从Clp_newModel()
检索到的完全相同的类的指针对象,它是一个指针(指向您从未处理过的内容)。
注意:您代码中的这部分可能不会按您的预期执行:
Clp_deleteModel(a.getPointer());
getPointer()
方法返回的是类的指针,而不是指向的值。在您的用法中,a
和 a.getPointer()
之间没有根本区别(除了类类型)。 (您可能要使用a.getValue()
,它会返回指向的值,这将是不同的,而且可能 不是 您想要的。)
当前您检索了一个PointerByReference
,因此您可以通过.getValue()
访问所指向的内容,这似乎是一个CLP_LINKAGE
,这似乎不是您将要操作的对象。因此,您可以在那里检索一个普通的Pointer
(不知道它指向什么)。然后,您将相同的指针传递给Clp-deleteModel(a)
。
如果您从未访问过指向的值,您可以简单地使用Pointer
,然而,通常最好的做法是为了限制API、类型安全性和自我说明代码,要定义一个扩展PointerType
的类。在您的情况下,CLPSimplexPtr extends PointerType
将是一个不错的选择。
如果需要理解返回的指针所指向的指针值(CLP_LINKAGE
),则使用适当的<whatever>ByReference
,并扩展ByReference
并实现setValue()
和getValue()
方法。
对您可能感兴趣的是,似乎有一个clp-java
项目,它使用BridJ
实现了CLP
,这是一个替代的Java到本地库的库(它使用JNA,但对C++进行了许多优化)。他们的定义是Pointer<CLPSimplex>
,对于两种映射都是如此,如果您在JNA中编写它,将与CLPSimplexPtr
类一致 -- 它仍然是一个装饰的普通指针,但是是类型安全的。
英文:
Looking at the CLP documentation, it appears that either Pointer
or PointerByReference
would work in this simplified example.
There are three general representations of pointers in JNA:
- The
Pointer
class, which has several methods for reading and writing from the pointed-to native memory. - The
PointerType
class, which can be extended to represent a pointer with no other functionality, better if you don't needPointer
functionality. - The collection of
<something>ByReference
classes, which are pointers to specific types of objects.
Since all you're ever doing is manipulating the pointer value, any of these would work: The more important point is that you pass a pointer object of the identical class that you retrieved from Clp_newModel()
which is a pointer (to something you never deal with).
Note: this part of your code may not be doing what you expect it to do:
Clp_deleteModel(a.getPointer());
The getPointer()
method returns the pointer of the class, not the value being pointed to. There's no fundamental difference (except class type) between a
and a.getPointer()
in your usage. (You might be meaning to use a.getValue()
which returns the pointed-to value, which would be different, and probably not what you want.)
Currently you retrieve a PointerByReference
so you have access (via .getValue()
) to what's being pointed to, which appears to be a CLP_LINKAGE
, which doesn't appear to be an object you'll ever manipulate. So you could retrieve a plain Pointer
there (without knowing what it points to) instead. And you would pass that same pointer to Clp-deleteModel(a)
.
If you are never accessing the pointed-to value, you can simply use Pointer
, however, it's generally a better practice for restricting the API, type safety, and self-documenting code to define a class extending PointerType
. In your case, CLPSimplexPtr extends PointerType
would be a good choice.
If there is a need to understand the pointer value (the CLP_LINKAGE
) that the returned poniter is being pointed at, then use the appropriate <whatever>ByReference
extending ByReference
and implementing the setValue()
and getValue()
methods.
Of possible interest to you, it seems there is a clp-java
project that implements CLP
using BridJ
, an alternative Java-to-native library (which uses JNA but has many optimizations for C++). Their definition is Pointer<CLPSimplex>
for both mappings, which would align with a CLPSimplexPtr
class if you wrote it in JNA -- it's still a decorated plain pointer, but a type-safe one.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论