simon
simon

Reputation: 77

Pass pointer or PointerByReference in JNA for pointer argument in C

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

Upvotes: 1

Views: 1648

Answers (1)

Daniel Widdis
Daniel Widdis

Reputation: 9091

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 <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.

Upvotes: 2

Related Questions