Skip to content

Commit d3b4379

Browse files
authored
Merge pull request #130 from javaevolved/copilot/simplify-c-code-java
Add "Calling out to C code from Java" pattern: JNI vs FFM API
2 parents 4ba22c3 + 361f9db commit d3b4379

File tree

14 files changed

+287
-1
lines changed

14 files changed

+287
-1
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
id: 113
3+
slug: "call-c-from-java"
4+
title: "Calling out to C code from Java"
5+
category: "language"
6+
difficulty: "advanced"
7+
jdkVersion: "22"
8+
oldLabel: "Java 1.1+"
9+
modernLabel: "Java 22+"
10+
oldApproach: "JNI (Java Native Interface)"
11+
modernApproach: "FFM (Foreign Function & Memory API)"
12+
oldCode: |-
13+
public class CallCFromJava {
14+
static { System.loadLibrary("strlen-jni"); }
15+
public static native long strlen(String s);
16+
public static void main(String[] args) {
17+
long ret = strlen("Bambi");
18+
System.out.println("Return value " + ret); // 5
19+
}
20+
}
21+
22+
// Run javac -h to generate the .h file, then write C:
23+
// #include "CallCFromJava.h"
24+
// #include <string.h>
25+
// JNIEXPORT jlong JNICALL Java_CallCFromJava_strlen(
26+
// JNIEnv *env, jclass clazz, jstring str) {
27+
// const char* s = (*env)->GetStringUTFChars(env, str, NULL);
28+
// jlong len = (jlong) strlen(s);
29+
// (*env)->ReleaseStringUTFChars(env, str, s);
30+
// return len;
31+
// }
32+
modernCode: |-
33+
void main() throws Throwable {
34+
try (var arena = Arena.ofConfined()) {
35+
// Use any system library directly — no C wrapper needed
36+
var stdlib = Linker.nativeLinker().defaultLookup();
37+
var foreignFuncAddr = stdlib.find("strlen").orElseThrow();
38+
var strlenSig = FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
39+
var strlenMethod = Linker.nativeLinker() .downcallHandle(foreignFuncAddr, strlenSig);
40+
var ret = (long) strlenMethod.invokeExact(arena.allocateFrom("Bambi"));
41+
IO.println("Return value " + ret); // 5
42+
}
43+
}
44+
45+
// Your own C library needs no special Java annotations:
46+
// long greet(char* name) {
47+
// printf("Hello %s\n", name);
48+
// return 0;
49+
// }
50+
summary: "FFM lets Java call C libraries directly, without JNI boilerplate or C-side Java knowledge."
51+
explanation: "Java has two approaches for calling native C/C++ code: the traditional\
52+
\ JNI and the modern FFM API. With JNI, you declare a method as native, run javac -h\
53+
\ to generate a C header file, then implement the function using the cumbersome JNI\
54+
\ C API (JNIEnv, jstring, etc.). FFM, introduced as a standard API in Java 22,\
55+
\ eliminates all of that: C code is just plain C — no JNI conventions needed. This\
56+
\ makes it far easier to call existing C/C++ libraries without modification. The\
57+
\ Java side uses Arena for safe off-heap memory management and MethodHandle for the\
58+
\ downcall, ensuring both flexibility and safety."
59+
whyModernWins:
60+
- icon: "👁"
61+
title: "C code stays plain C"
62+
desc: "The C function requires no JNI annotations or JNIEnv boilerplate — any existing C library can be called as-is."
63+
- icon: ""
64+
title: "More flexible"
65+
desc: "Directly call most existing C/C++ libraries without writing adapter code or generating header files."
66+
- icon: "🛠️"
67+
title: "Easier workflow"
68+
desc: "No need to stop, run javac -h, and implement the interface defined in the generated .h file."
69+
support:
70+
state: "available"
71+
description: "Standardized in JDK 22 (March 2024); previously incubating since JDK 14"
72+
prev: "language/compact-canonical-constructor"
73+
next: "enterprise/servlet-vs-jaxrs"
74+
related:
75+
- "io/file-memory-mapping"
76+
- "language/compact-source-files"
77+
- "language/unnamed-variables"
78+
docs:
79+
- title: "JEP 454: Foreign Function & Memory API"
80+
href: "https://openjdk.org/jeps/454"
81+
- title: "java.lang.foreign package (Java 22)"
82+
href: "https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/package-summary.html"

content/language/compact-canonical-constructor.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ support:
4848
state: "available"
4949
description: "Widely available since JDK 16 (March 2021)"
5050
prev: "language/static-members-in-inner-classes"
51-
next: "enterprise/servlet-vs-jaxrs"
51+
next: "language/call-c-from-java"
5252
related:
5353
- "language/records-for-data-classes"
5454
- "language/flexible-constructor-bodies"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: "استدعاء كود C من Java"
2+
oldApproach: "JNI (واجهة Java الأصيلة)"
3+
modernApproach: "FFM (واجهة برمجة الدوال الخارجية والذاكرة)"
4+
summary: "تتيح FFM لـ Java استدعاء مكتبات C مباشرةً، دون الحاجة إلى كليشيهات JNI أو معرفة Java على جانب C."
5+
explanation: "تمتلك Java نهجين لاستدعاء كود C/C++ الأصيل: JNI التقليدي وواجهة FFM الحديثة. مع JNI، تُعلن عن الدالة بوصفها native، ثم تُشغّل javac -h لتوليد ملف ترويسة C، وتُنفّذ الدالة باستخدام JNI C API المعقّدة (JNIEnv وjstring وما إلى ذلك). تُزيل FFM المُقدَّمة كواجهة برمجة قياسية في Java 22 كل ذلك: كود C يبقى C عادياً — دون الحاجة لاتفاقيات JNI. هذا يُسهّل استدعاء مكتبات C/C++ الموجودة دون تعديل. يستخدم الجانب Java كائن Arena لإدارة الذاكرة خارج الكومة بأمان، وMethodHandle للاستدعاء النازل، مما يضمن المرونة والأمان."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: "كود C يبقى C نقياً"
9+
desc: "لا تحتاج دالة C إلى تعليقات JNI أو كليشيهات JNIEnv — يمكن استدعاء أي مكتبة C موجودة مباشرةً."
10+
- icon: ""
11+
title: "أكثر مرونة"
12+
desc: "استدعِ معظم مكتبات C/C++ الموجودة مباشرةً دون كتابة كود محوّل أو توليد ملفات ترويسة."
13+
- icon: "🛠️"
14+
title: "سير عمل أسهل"
15+
desc: "لا حاجة للتوقف وتشغيل javac -h وتنفيذ الواجهة المُعرَّفة في ملف .h المُوَلَّد."
16+
support:
17+
description: "تم توحيده في JDK 22 (مارس 2024)؛ كان في مرحلة الحضانة منذ JDK 14"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: Java থেকে C কোড কল করা
2+
oldApproach: JNI (Java Native Interface)
3+
modernApproach: FFM (Foreign Function & Memory API)
4+
summary: FFM জাভাকে JNI বয়লারপ্লেট বা C-সাইডে Java জ্ঞান ছাড়াই সরাসরি C লাইব্রেরি কল করতে দেয়।
5+
explanation: "Java-তে নেটিভ C/C++ কোড কল করার দুটি পদ্ধতি রয়েছে: ঐতিহ্যগত JNI এবং আধুনিক FFM API। JNI-এর সাথে, আপনি একটি মেথড native হিসেবে ঘোষণা করেন, C হেডার ফাইল তৈরি করতে javac -h চালান, তারপর কষ্টকর JNI C API (JNIEnv, jstring ইত্যাদি) ব্যবহার করে ফাংশন ইমপ্লিমেন্ট করেন। Java 22-এ স্ট্যান্ডার্ড API হিসেবে প্রবর্তিত FFM এই সব বাদ দেয়: C কোড শুধু সাধারণ C — কোনো JNI কনভেনশন প্রয়োজন নেই। এটি পরিবর্তন ছাড়াই বিদ্যমান C/C++ লাইব্রেরি কল করা অনেক সহজ করে তোলে। Java সাইড নিরাপদ অফ-হিপ মেমরি ম্যানেজমেন্টের জন্য Arena এবং ডাউনকলের জন্য MethodHandle ব্যবহার করে, যা নমনীয়তা এবং নিরাপত্তা উভয়ই নিশ্চিত করে।"
6+
whyModernWins:
7+
- icon: "👁"
8+
title: C কোড সাদামাটা C-ই থাকে
9+
desc: C ফাংশনে কোনো JNI অ্যানোটেশন বা JNIEnv বয়লারপ্লেট প্রয়োজন নেই — যেকোনো বিদ্যমান C লাইব্রেরি যেমন আছে তেমনি কল করা যায়।
10+
- icon: ""
11+
title: আরও নমনীয়
12+
desc: অ্যাডাপ্টার কোড লেখা বা হেডার ফাইল তৈরি না করেই বেশিরভাগ বিদ্যমান C/C++ লাইব্রেরি সরাসরি কল করুন।
13+
- icon: "🛠️"
14+
title: সহজতর ওয়ার্কফ্লো
15+
desc: "থামার, javac -h চালানোর এবং জেনারেটেড .h ফাইলে সংজ্ঞায়িত ইন্টারফেস ইমপ্লিমেন্ট করার প্রয়োজন নেই।"
16+
support:
17+
description: JDK 22-এ মানসম্পন্ন (মার্চ 2024); পূর্বে JDK 14 থেকে ইনকিউবেটিং
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: "C-Code aus Java aufrufen"
2+
oldApproach: "JNI (Java Native Interface)"
3+
modernApproach: "FFM (Foreign Function & Memory API)"
4+
summary: "FFM ermöglicht es Java, C-Bibliotheken direkt aufzurufen, ohne JNI-Boilerplate oder Java-Kenntnisse auf der C-Seite."
5+
explanation: "Java bietet zwei Ansätze zum Aufrufen von nativem C/C++-Code: das traditionelle JNI und die moderne FFM API. Bei JNI deklarieren Sie eine Methode als native, führen javac -h aus, um eine C-Header-Datei zu generieren, und implementieren die Funktion mit der umständlichen JNI-C-API (JNIEnv, jstring usw.). FFM, als Standard-API in Java 22 eingeführt, eliminiert all das: C-Code bleibt reines C — keine JNI-Konventionen erforderlich. Dies macht es viel einfacher, bestehende C/C++-Bibliotheken ohne Änderungen aufzurufen. Die Java-Seite verwendet Arena für sicheres Off-Heap-Speichermanagement und MethodHandle für den Downcall, was sowohl Flexibilität als auch Sicherheit gewährleistet."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: "C-Code bleibt reines C"
9+
desc: "Die C-Funktion benötigt keine JNI-Annotationen oder JNIEnv-Boilerplate — jede vorhandene C-Bibliothek kann direkt aufgerufen werden."
10+
- icon: ""
11+
title: "Flexibler"
12+
desc: "Die meisten vorhandenen C/C++-Bibliotheken können direkt aufgerufen werden, ohne Adaptercode zu schreiben oder Header-Dateien zu generieren."
13+
- icon: "🛠️"
14+
title: "Einfacherer Workflow"
15+
desc: "Kein Stoppen, kein Ausführen von javac -h und kein Implementieren der in der generierten .h-Datei definierten Schnittstelle."
16+
support:
17+
description: "In JDK 22 standardisiert (März 2024); zuvor seit JDK 14 in der Inkubationsphase"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: Llamar a código C desde Java
2+
oldApproach: JNI (Java Native Interface)
3+
modernApproach: FFM (Foreign Function & Memory API)
4+
summary: FFM permite a Java llamar directamente a bibliotecas C sin el código repetitivo de JNI ni conocimiento de Java en el lado C.
5+
explanation: "Java tiene dos enfoques para llamar a código nativo C/C++: el tradicional JNI y la moderna API FFM. Con JNI, se declara un método como native, se ejecuta javac -h para generar un archivo de encabezado C y se implementa la función usando la complicada API JNI de C (JNIEnv, jstring, etc.). FFM, introducida como API estándar en Java 22, elimina todo eso: el código C es simplemente C puro — sin necesidad de convenciones JNI. Esto facilita mucho la llamada a bibliotecas C/C++ existentes sin modificaciones. El lado Java usa Arena para la gestión segura de memoria fuera del heap y MethodHandle para el downcall, garantizando flexibilidad y seguridad."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: El código C permanece como C puro
9+
desc: "La función C no requiere anotaciones JNI ni código JNIEnv repetitivo — cualquier biblioteca C existente puede llamarse tal cual."
10+
- icon: ""
11+
title: Más flexible
12+
desc: "Llama directamente a la mayoría de las bibliotecas C/C++ existentes sin escribir código adaptador ni generar archivos de encabezado."
13+
- icon: "🛠️"
14+
title: Flujo de trabajo más sencillo
15+
desc: "No es necesario detenerse, ejecutar javac -h e implementar la interfaz definida en el archivo .h generado."
16+
support:
17+
description: Estandarizado en JDK 22 (marzo 2024); anteriormente en incubación desde JDK 14
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: Appeler du code C depuis Java
2+
oldApproach: JNI (Java Native Interface)
3+
modernApproach: FFM (Foreign Function & Memory API)
4+
summary: FFM permet à Java d'appeler directement des bibliothèques C, sans code répétitif JNI ni connaissance de Java côté C.
5+
explanation: "Java propose deux approches pour appeler du code natif C/C++ : le JNI traditionnel et la moderne API FFM. Avec JNI, vous déclarez une méthode comme native, exécutez javac -h pour générer un fichier d'en-tête C, puis implémentez la fonction en utilisant la lourde API JNI C (JNIEnv, jstring, etc.). FFM, introduite comme API standard dans Java 22, élimine tout cela : le code C reste du C pur — aucune convention JNI n'est requise. Cela facilite considérablement l'appel de bibliothèques C/C++ existantes sans modification. Le côté Java utilise Arena pour la gestion sécurisée de la mémoire hors tas et MethodHandle pour le downcall, garantissant flexibilité et sécurité."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: Le code C reste du C pur
9+
desc: "La fonction C n'a besoin d'aucune annotation JNI ni de code JNIEnv répétitif — toute bibliothèque C existante peut être appelée telle quelle."
10+
- icon: ""
11+
title: Plus flexible
12+
desc: "Appelez directement la plupart des bibliothèques C/C++ existantes sans écrire de code adaptateur ni générer de fichiers d'en-tête."
13+
- icon: "🛠️"
14+
title: Workflow simplifié
15+
desc: "Inutile de s'arrêter, d'exécuter javac -h et d'implémenter l'interface définie dans le fichier .h généré."
16+
support:
17+
description: Standardisé dans JDK 22 (mars 2024) ; auparavant en incubation depuis JDK 14
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: Chiamare codice C da Java
2+
oldApproach: JNI (Java Native Interface)
3+
modernApproach: FFM (Foreign Function & Memory API)
4+
summary: "FFM consente a Java di chiamare direttamente librerie C, senza boilerplate JNI né conoscenza di Java lato C."
5+
explanation: "Java offre due approcci per chiamare codice nativo C/C++: il tradizionale JNI e la moderna API FFM. Con JNI, si dichiara un metodo come native, si esegue javac -h per generare un file di intestazione C, quindi si implementa la funzione usando la complicata JNI C API (JNIEnv, jstring, ecc.). FFM, introdotta come API standard in Java 22, elimina tutto ciò: il codice C rimane puro C — nessuna convenzione JNI richiesta. Questo rende molto più semplice chiamare librerie C/C++ esistenti senza modifiche. Il lato Java usa Arena per la gestione sicura della memoria off-heap e MethodHandle per il downcall, garantendo flessibilità e sicurezza."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: Il codice C rimane C puro
9+
desc: "La funzione C non richiede annotazioni JNI né boilerplate JNIEnv — qualsiasi libreria C esistente può essere chiamata così com'è."
10+
- icon: ""
11+
title: Più flessibile
12+
desc: "Chiama direttamente la maggior parte delle librerie C/C++ esistenti senza scrivere codice adattatore né generare file di intestazione."
13+
- icon: "🛠️"
14+
title: Flusso di lavoro più semplice
15+
desc: "Nessuna necessità di fermarsi, eseguire javac -h e implementare l'interfaccia definita nel file .h generato."
16+
support:
17+
description: Standardizzato in JDK 22 (marzo 2024); precedentemente in incubazione da JDK 14
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: JavaからCコードを呼び出す
2+
oldApproach: JNI(Java Native Interface)
3+
modernApproach: FFM(Foreign Function & Memory API)
4+
summary: "FFMを使えば、JNIのボイラープレートやC側でのJavaの知識なしに、JavaからCライブラリを直接呼び出せる。"
5+
explanation: "Javaにはネイティブな C/C++ コードを呼び出す2つのアプローチがあります:従来のJNIとモダンなFFM APIです。JNIでは、メソッドをnativeとして宣言し、javac -hを実行してCヘッダーファイルを生成し、煩雑なJNI C API(JNIEnv、jstringなど)を使って関数を実装する必要があります。Java 22で標準APIとして導入されたFFMは、そのすべてを不要にします:Cコードはただの普通のC — JNIの慣例は不要です。これにより、既存のC/C++ライブラリを変更なしに呼び出すことがはるかに容易になります。Javaサイドでは、安全なオフヒープメモリ管理にArenaを、ダウンコールにMethodHandleを使用し、柔軟性と安全性の両方を確保します。"
6+
whyModernWins:
7+
- icon: "👁"
8+
title: Cコードは普通のCのまま
9+
desc: "C関数にJNIアノテーションもJNIEnvのボイラープレートも不要 — 既存のCライブラリをそのまま呼び出せます。"
10+
- icon: ""
11+
title: より柔軟
12+
desc: "アダプターコードを書いたりヘッダーファイルを生成したりせずに、ほとんどの既存C/C++ライブラリを直接呼び出せます。"
13+
- icon: "🛠️"
14+
title: ワークフローが簡単
15+
desc: "javac -hを実行して生成された.hファイルで定義されたインターフェースを実装するために作業を止める必要がありません。"
16+
support:
17+
description: JDK 22で標準化(2024年3月);JDK 14からインキュベーション中
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
title: "Java에서 C 코드 호출하기"
2+
oldApproach: "JNI (Java Native Interface)"
3+
modernApproach: "FFM (Foreign Function & Memory API)"
4+
summary: "FFM은 JNI 보일러플레이트나 C 측의 Java 지식 없이 Java가 C 라이브러리를 직접 호출할 수 있게 합니다."
5+
explanation: "Java에는 네이티브 C/C++ 코드를 호출하는 두 가지 접근 방식이 있습니다: 전통적인 JNI와 현대적인 FFM API입니다. JNI를 사용하면 메서드를 native로 선언하고, javac -h를 실행하여 C 헤더 파일을 생성한 다음, 번거로운 JNI C API(JNIEnv, jstring 등)를 사용하여 함수를 구현해야 합니다. Java 22에서 표준 API로 도입된 FFM은 이 모든 것을 없애줍니다: C 코드는 그냥 순수한 C — JNI 규약이 필요 없습니다. 이를 통해 기존 C/C++ 라이브러리를 수정 없이 훨씬 쉽게 호출할 수 있습니다. Java 측에서는 안전한 오프힙 메모리 관리를 위해 Arena를, 다운콜을 위해 MethodHandle을 사용하여 유연성과 안전성을 모두 보장합니다."
6+
whyModernWins:
7+
- icon: "👁"
8+
title: "C 코드는 순수한 C 그대로"
9+
desc: "C 함수에는 JNI 어노테이션이나 JNIEnv 보일러플레이트가 필요 없습니다 — 기존 C 라이브러리를 그대로 호출할 수 있습니다."
10+
- icon: ""
11+
title: "더 유연함"
12+
desc: "어댑터 코드를 작성하거나 헤더 파일을 생성하지 않고도 대부분의 기존 C/C++ 라이브러리를 직접 호출할 수 있습니다."
13+
- icon: "🛠️"
14+
title: "더 쉬운 워크플로"
15+
desc: "멈춰서 javac -h를 실행하고 생성된 .h 파일에 정의된 인터페이스를 구현할 필요가 없습니다."
16+
support:
17+
description: "JDK 22에서 표준화됨 (2024년 3월); 이전에는 JDK 14부터 인큐베이팅"

0 commit comments

Comments
 (0)