Fortranを「C言語の操り人形」にする技術:ISO_C_BINDINGと関数ポインタの深淵
こんにちは。かつて宇宙の深淵を数値計算で解き明かしていた者です。
君たちが今、CやPythonからFortranの世界へ足を踏み入れ、「なぜ2024年にもなってFortranなのか?」と疑問を抱いていることは重々承知しています。答えは単純。この言語は、メモリの深層心理を知り尽くした「計算の暴力的な加速装置」だからです。
今日は、そんなFortranの力をC言語やPythonといった「外の世界」と繋ぐための最強の技術、『ISO_C_BINDING』による関数ポインタの受け渡しについて解説します。
—
1. なぜ「関数ポインタ」を渡す必要があるのか?
C言語やPython(ctypes経由)からFortranを呼び出す際、単なる数値計算なら簡単ですが、複雑なシミュレーションになると「計算の途中で、外部から与えられた関数(コールバック関数)を呼び出したい」という場面に必ず遭遇します。
しかし、Fortranのプロシージャ(サブルーチンや関数)は、メモリ上での持ち方がCとは全く異なります。そのまま渡そうとしても、Cのポインタ側は「どこを指しているのかわからない」とパニックを起こします。ここで登場するのが `ISO_C_BINDING` です。
2. 実践:C言語へFortranの魂を渡す
まずは、Fortran側で「私をC言語風に扱ってください」と宣言する儀式が必要です。
module callback_module
use, intrinsic :: iso_c_binding
implicit none
! C言語側で定義された関数のインターフェースをFortranに教える
interface
subroutine c_executor(func_ptr) bind(c)
import :: c_funptr
type(c_funptr), value :: func_ptr
end subroutine c_executor
end interface
contains
! C言語に渡すためのFortran関数
! bind(c)をつけることで、Cのシンボルとして名前が公開される
subroutine my_fortran_logic() bind(c, name=”fortran_callback”)
print , “Fortranの深淵からこんにちは!”
end subroutine my_fortran_logic
end module callback_module
ここがポイント!
- `bind(c)`: これを付与するだけで、コンパイラはFortran特有の「余計なお世話(引数の自動的な隠し参照渡しなど)」を排除し、C言語とガチンコ勝負できる形式に変換してくれます。
- `c_funptr`: これはC言語の `void` に相当する、関数ポインタを格納するための箱です。
3. 現場で泣かないための「関数ポインタ」の渡し方
Fortran側で定義した関数を、どうやってC言語の実行エンジンに渡すのか。ここが一番のハマりどころです。
subroutine run_simulation()
use, intrinsic :: iso_c_binding
use callback_module
! c_funlocは、Fortranの関数を「C言語が理解できるポインタ」に変換する魔法の関数
type(c_funptr) :: p_func
p_func = c_funloc(my_fortran_logic)
! C言語側の実行関数にポインタを渡す
call c_executor(p_func)
end subroutine run_simulation
ここで重要な知見を一つ。`c_funloc` で取得したポインタは、そのプロシージャがメモリ上で静的に配置されていることが前提です。動的なメモリアロケーションの対象や、スコープから外れるような関数を無理やり渡すと、セグメンテーションフォールト(メモリの闇)に引きずり込まれます。必ず `module` 内に閉じ込めるか、`save` 属性をつけて生存期間を保証してください。
4. コンパイラの最適化とリンクの泥臭い話
コードが書けたら、ビルドです。ここで最適化のフラグを適当に選ぶと、パフォーマンスをドブに捨てることになります。
gfortranの例
-O3 は絶対。-flto (Link Time Optimization) をつけることで、
CとFortranの境界をまたいだインライン展開が期待できます。
gfortran -c -O3 -flto my_code.f90
gcc -c -O3 -flto main.c
gcc -o simulation main.o my_code.o -lgfortran
特に数値計算の現場では、「行列の列優先順位(Column-Major)」というFortranの掟を忘れないでください。C言語の行列(行優先)と混ぜて使う場合、インデックスを転置させるか、メモリアクセスの局所性を意識したループ設計をしないと、せっかくのモダンFortranもCPUキャッシュミスで台無しになります。
最後に:若手エンジニアへ
Fortranは古い言語と言われますが、それは「計算の基礎物理」を最も正直に記述できる言語であるという証左です。C言語のポインタの柔軟さと、Fortranのベクトル演算の純粋さを混ぜ合わせるこの技術は、君たちの武器になります。
まずはコンパイルを通すところから。エラーが出たら、それはコンパイラからの「もう少しメモリの構造を意識してくれ」という愛のメッセージだと思ってください。
さあ、今日から君のプログラムを「計算の最前線」へと送り出しましょう!何か詰まったら、いつでも戻ってきてください。現場の知見を、また共有します。

コメント