159. Calling the sumTwoInt() foreign function
Do you remember the sumTwoInt() function? We have defined this C function in a native shared library named math.dll (check Problems 137, 138, and 139). Let’s assume that we have placed the math.dll library in the project folder under the lib/cpp path.We can call this foreign function in almost the same manner as we’ve called _getpid(). Since math.dll is a user-defined library that is not part of commonly used libraries it cannot be loaded via defaultLookup(). The solution is to explicitly load the library from the lib/cpp path as follows:
Linker linker = Linker.nativeLinker();
Path path = Paths.get(“lib/cpp/math.dll”);
try (Arena arena = Arena.openConfined()) {
SymbolLookup libLookup = SymbolLookup.libraryLookup(
path, arena.scope());
…
Next, we have to find in math.dll the foreign function by name. If your C compiler (for instance, G++) has applied the mangling (or, name decoration) technique then sumTwoInt was renamed in the library to something else (here, _Z9sumTwoIntii) and that name should be used:
MemorySegment segmentSumTwoInt
= libLookup.find(“_Z9sumTwoIntii”).get();
…
Next, we define the MethodHandle for this downcall:
MethodHandle func = linker.downcallHandle(segmentSumTwoInt,
FunctionDescriptor.of(ValueLayout.JAVA_LONG,
ValueLayout.JAVA_INT, ValueLayout.JAVA_INT));
…
Finally, we can invoke the foreign function and get the result:
long result = (long) func.invokeExact(3, 9);
System.out.println(result);
}
The result should be 12. Check out the complete code in the bundled code.
160. Calling the modf() foreign function
Let’s consider that we want to call the modf() foreign function. This function is part of the C standard library having the following syntax (https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/modf-modff-modfl):
double modf(double x, double *intptr);
This method gets a double x and returns the signed fractional part of x. The intptr is a pointer argument used to point to the memory address where the integer part should be stored as a double value.Since this method is part of UCRT, it can be found via defaultLookup():
Linker linker = Linker.nativeLinker();
SymbolLookup libLookup = linker.defaultLookup();
try (Arena arena = Arena.openConfined()) {
MemorySegment segmentModf = libLookup.find(“modf”).get();
…
Nothing new so far! Next, we need to define the proper MethodHandle. Because the second argument of modf() is a pointer, we need to specify a value layout of type ADDRESS:
MethodHandle func = linker.downcallHandle(segmentModf,
FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE,
ValueLayout.JAVA_DOUBLE, ValueLayout.ADDRESS));
…
If we could invoke the foreign function at this moment we could collect the fractional part of the given x, but we cannot obtain the integer part. We have to create a memory segment and pass this memory segment to the foreign function at invocation time. The foreign function will write the integer part in this memory segment that should be capable to store a double value:
MemorySegment segmentIntptr
= arena.allocate(ValueLayout.JAVA_DOUBLE);
double fractional
= (double) func.invokeExact(x, segmentIntptr);
…
The fractional part is returned by the foreign key. The integer part is read from the memory segment at offset 0:
System.out.println(“Fractional part: ” + fractional
+ ” Integer part: ” + segmentIntptr.get(
ValueLayout.JAVA_DOUBLE, 0));
}
If x = 89.76655 then the output will be:
Fractional part: 0.7665499999999952 Integer part: 89.0
Challenge yourself to adapt this code to call modff() and modfl() foreign functions.