Category
language
Slug
call-c-from-java
Title
Calling out to C code from Java
Difficulty
advanced
Since JDK
22
Summary
Simplifies C/C++ code to be called from Java, allowing most existing libraries to be used without adapters or cumbersome C code modification.
Old code label
Java 1.1+
Old code
publicclassCallCFromJava {
static { System.loadLibrary("hello-jni"); }
publicstaticnativeintgreet(Stringname);
publicstaticvoidmain(String[] args) {
intret = greet("Bambi");
System.out.println("Return value " + ret);
}
}
Thenrunjavac -h, thenviewthegenerated .hfile, thenwriteyour .cfile:
#include"CallCFromJava.h"JNIEXPORTintJNICALLJava_CallCFromJava_greet(JNIEnv *env, jclassthis, jstringstr) {
constchar* name = (*env)->GetStringUTFChars(env, str, NULL);
printf("Hello %s\n", name);
return0;
}Modern code label
Java 22+
Modern code
publicclassCallCFromJava {
voidmain() throwsThrowable {
try (Arenaarena = Arena.ofConfined()) {
SymbolLookupourLib = SymbolLookup.libraryLookup("libhello-ffi.so", arena);
Optional<MemorySegment> segment = ourLib.find("greet");
MemorySegmentforeignFuncAddr = segment.get();
FunctionDescriptorgreet_sig= // return and input parameterFunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
MethodHandlegreetMethod =
Linker.nativeLinker().downcallHandle(foreignFuncAddr, greet_sig);
varret = (long) greetMethod.invokeExact(arena.allocateFrom("Bambi"));
System.out.println("Return value " + ret);
}
}
}
CCode:
intgreet(char* name) {
printf("Hello %s\n", name);
return0;
}Explanation
Java has two techniques for interfacing between Java and C/C++ code, the traditional JNI and the newer FFM. With JNI you simply declare your method as native, but then you have to run javac -h to generate a C-language .h (header) file, then have your C code implement that, and deal with the slightly cumbersome JNI C-language API.
FFM simplifies the C code to the point that it doesn't have to know anything about Java. This makes it much easier to interface with existing C/C++-language libraries. It does take a few more lines of Java code, but the net effect is more readable and more maintainable. Compare the C code in both versions and you'll see the difference!
Minimal runnable demo can be found at https://github.com/IanDarwin/javaevolved-java_callling_c
Why the modern way wins
👁 Better readability — C code doesn't have to learn Java!
⚡ More flexible - can directly call most existing C/C++ libraries
⚡ Easier - don't have to stop, run javac -h, and implement the "interface" defined in .h file.
Category
language
Slug
call-c-from-java
Title
Calling out to C code from Java
Difficulty
advanced
Since JDK
22
Summary
Simplifies C/C++ code to be called from Java, allowing most existing libraries to be used without adapters or cumbersome C code modification.
Old code label
Java 1.1+
Old code
Modern code label
Java 22+
Modern code
Explanation
Java has two techniques for interfacing between Java and C/C++ code, the traditional JNI and the newer FFM. With JNI you simply declare your method as native, but then you have to run
javac -hto generate a C-language .h (header) file, then have your C code implement that, and deal with the slightly cumbersome JNI C-language API.FFM simplifies the C code to the point that it doesn't have to know anything about Java. This makes it much easier to interface with existing C/C++-language libraries. It does take a few more lines of Java code, but the net effect is more readable and more maintainable. Compare the C code in both versions and you'll see the difference!
Minimal runnable demo can be found at https://github.com/IanDarwin/javaevolved-java_callling_c
Why the modern way wins
👁 Better readability — C code doesn't have to learn Java!
⚡ More flexible - can directly call most existing C/C++ libraries
⚡ Easier - don't have to stop, run javac -h, and implement the "interface" defined in .h file.