FortranとCを繋ぐ「共通言語」:BIND(C)属性の極意
こんにちは。長年、スパコンの冷却音を子守唄にして数値シミュレーションの最適化と格闘してきた、元宇宙航空研究機関の数値計算アーキテクトです。
さて、皆さんのようなモダンなエンジニアがFortranの世界に足を踏み入れたとき、最初にぶつかる壁が「どうやって他の言語(CやPython)と連携するか」という点ですよね。現代の数値計算において、ライブラリの資産が豊富なFortranと、UIやエコシステムに優れたPythonやCを組み合わせるのは避けて通れない道です。
今回は、FortranのプロシージャをC言語から「見える」ようにするための魔法の鍵、`BIND(C)`について、現場の泥臭い経験を交えて解説します。
—
なぜ「そのまま」では繋がらないのか?
まず、FortranとCは「言葉の訛り」が違います。
Fortranは古くから、引数をすべて「参照渡し(ポインタ経由)」で扱うという強力な文化を持っています。対してCは「値渡し」を基本とし、配列もポインタで管理します。
何もせずに関数を外部公開しても、C言語のコンパイラはFortran側で修飾された(名前が勝手に変わったり、末尾にアンダースコアが付いたりする)シンボルを見つけることができません。ここで登場するのが `BIND(C)` です。
—
BIND(C)の基本:翻訳機を差し込む
`BIND(C)` は、Fortranの関数を「C言語の規約(Calling Convention)に従って出力しなさい」というコンパイラへの命令です。
実装例:シンプルな計算ユニット
例えば、2つの数値を足し合わせるシンプルな関数をCから呼び出せるようにしてみましょう。
! 外部公開用モジュール
module math_kernel
use iso_c_binding, only: c_double
implicit none
contains
! BIND(C) を付与し、C言語側の関数名を明示する
function add_numbers(a, b) bind(c, name=”my_add_numbers”) result(res)
! 引数はすべてCの型に合わせるのが鉄則です
real(c_double), value :: a, b
real(c_double) :: res
res = a + b
end function add_numbers
end module math_kernel
ポイント解説
1. `iso_c_binding` の利用: これは必須です。`c_double` や `c_int` を使うことで、FortranとCの型サイズが確実に一致することを保証します。ここをサボると、CPUアーキテクチャの違いで数値が化けるという、最もデバッグが困難な地獄を見ることになります。
2. `value` 属性: `BIND(C)` を使う際、引数に `value` を付けないと、C言語側からは「値そのもの」ではなく「値へのポインタ」を渡さなければならなくなります。数値計算用なら `value` を使うのが直感的です。
3. `name` 属性: これが非常に重要です。`name=”my_add_numbers”` と指定することで、Fortranの関数名がなんであれ、C言語からは確実に `my_add_numbers` という名前で呼び出せるようになります。
—
現場で泣かないための「境界線」の守り方
数値計算の現場で最も多い事故が「メモリレイアウトの不一致」です。
1. 配列の順序(Column-Major vs Row-Major)
Fortranは「列優先(Column-Major)」、CやPython(NumPy)は「行優先(Row-Major)」です。
もし大きな行列を渡す場合、そのまま扱うと計算結果が転置されてしまいます。現場では、「Fortran側のインターフェースで転置を吸収する」か、「あらかじめC側でメモリレイアウトをFortranに合わせて確保する」という設計思想を最初から決めておく必要があります。
2. 文字列の受け渡し
文字列の受け渡しは鬼門です。Fortranの文字列は「長さ情報」を裏で持っていますが、C言語にはありません。`iso_c_binding` の `c_char` 型と `c_ptr` を使い、ヌル終端文字を意識した実装を心がけてください。
—
コンパイルとリンクの作法
最後に、これをビルドする際のヒントです。モダンなプロジェクトでは、`gfortran` や `ifort` (ifx) を使うのが一般的ですが、リンク時にはC側のオブジェクトとFortranのランタイムを正しく結合する必要があります。
Fortranコードをコンパイル
gfortran -c math_kernel.f90 -o math_kernel.o
Cのメインプログラムとリンク(gfortranはランタイムライブラリを自動でリンクしてくれます)
gcc main.c math_kernel.o -lgfortran -o simulation_run
—
最後に:皆さんへのエール
`BIND(C)` を使いこなせれば、Fortranの計算速度と、C/Pythonの柔軟性という「いいとこ取り」が可能になります。
最初はエラーログが真っ赤になって絶望するかもしれませんが、それは皆さんが新しい技術の境界線を越えようとしている証拠です。まずは小さな関数を一つ、C言語から呼び出すことに成功させてみてください。その瞬間に、Fortranという強力な武器を、現代のあらゆるシステムに組み込めるようになります。
何かあればいつでも聞いてくださいね。皆さんの数値計算ライフが、最適化された素晴らしいものになることを応援しています!

コメント