Pass pointer or PointerByReference in JNA for pointer argument in C

huangapple go评论93阅读模式
英文:

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文档,似乎在这个简化的示例中,PointerPointerByReference都可以使用。

JNA中有三种一般的指针表示方式:

  • Pointer类,它有几种方法用于从指向的本地内存中读取和写入。
  • PointerType类,可以扩展它以表示一个没有其他功能的指针,如果您不需要Pointer功能,则更好。
  • 一系列的<something>ByReference类,它们是指向特定类型对象的指针。

因为您所做的一切都是操作指针值,所以这些都可以工作:更重要的是,您传递一个与从Clp_newModel()检索到的完全相同的类的指针对象,它是一个指针(指向您从未处理过的内容)。

注意:您代码中的这部分可能不会按您的预期执行:

Clp_deleteModel(a.getPointer());

getPointer()方法返回的是类的指针,而不是指向的值。在您的用法中,aa.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 need Pointer functionality.
  • The collection of &lt;something&gt;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 &lt;whatever&gt;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&lt;CLPSimplex&gt; 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.

huangapple
  • 本文由 发表于 2020年10月13日 02:29:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/64323404.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定