C言語のメモリをFortranで「魔改造」する:C_F_POINTERの極意
こんにちは。元宇宙航空研究機関で、数テラバイトの流体シミュレーションと格闘してきた者です。
C言語やPythonを触ってきた皆さんがFortranの世界へ足を踏み入れると、最初にぶつかる壁が「メモリ管理」です。Fortranは本来、コンパイラがメモリを自動管理する「お行儀の良い」言語ですが、大規模な数値計算の現場では、「C言語で確保した巨大なデータ領域を、Fortranの高速な配列として直接叩きたい」という切実な要求が必ず発生します。
そこで登場するのが `ISO_C_BINDING` モジュールの `C_F_POINTER` です。これ、単なる「型変換」だと思ったら大間違い。CPUのキャッシュ効率とFortranの最適化能力を最大限に引き出すための、極めて重要な儀式なんです。
—
なぜ「コピー」してはいけないのか?
まず大前提ですが、Cで作った巨大配列をFortran側に渡すとき、要素ごとにコピーを作成するのは「禁じ手」です。メモリの無駄ですし、何よりキャッシュミスが多発して計算速度が劇的に落ちます。
我々がやりたいのは、「Cが確保したメモリの住所(ポインタ)を、Fortranの配列として名前を付けてあげる」という、メモリへの「ラベル貼り」のような操作です。
—
1. 魔法の呪文 `ISO_C_BINDING` を召喚する
まずは、Cとの架け橋となるモジュールを呼び出しましょう。これがなければ始まりません。
module memory_bridge
use, intrinsic :: iso_c_binding
implicit none
contains
subroutine map_c_memory(c_ptr, n)
type(c_ptr), value :: c_ptr ! Cからのポインタを受け取る
integer(c_int), value :: n ! 配列のサイズ
! Fortran側の配列ポインタを定義
real(c_double), pointer :: f_array(:)
! 魔法の関数:CのポインタをFortranの配列にキャストする
call c_f_pointer(c_ptr, f_array, [n])
! ここからf_arrayは、Cのメモリを直接参照するFortran配列として振る舞う
! 読み書きは高速なFortranの最適化が適用される
f_array(1) = 1.0d0
end subroutine
end module
—
2. 泥臭い注意点:列優先順位(Column-Major)の罠
ここで一つ、現場のエンジニアが必ずハマる「地雷」についてお話しします。
Fortranは「列優先(Column-Major)」です。一方でC言語は「行優先(Row-Major)」。ここを理解せずに配列をマッピングすると、計算結果が壊滅的なことになります。
- Cのメモリ配置: `a[0][0], a[0][1], a[0][2]…` (行が先に変わる)
- Fortranのメモリ配置: `a(1,1), a(2,1), a(3,1)…` (列が先に変わる)
もし多次元配列(行列など)をマッピングするなら、C言語側の配列構造と、Fortran側の添字の持ち方を完全に一致させる必要があります。もしCで `data[N][M]` と確保しているなら、Fortran側では `real(c_double), pointer :: f_array(:, :)` と定義し、`shape`引数で `[M, N]` と指定してあげる工夫が必要です。
—
3. 最適化のための「極限の知見」
現場で生き残るために、以下の3点を心に刻んでおいてください。
1. Contiguous(連続性)の保証:
`C_F_POINTER` でマッピングした配列は、Fortran側から見て「メモリが連続している」とコンパイラが認識すると、SIMDベクトル化(CPUの並列演算機能)が一気に加速します。コードを書く際は、できるだけフラットな1次元配列として扱い、インデックス計算を工夫する方がトラブルが少ないです。
2. 型の一致:
Cの `double` はFortranの `real(c_double)`、`int` は `integer(c_int)`。ここをケチって適当な型を当てると、メモリのアライメント(境界調整)がズレて、計算速度が1/10になるどころか、セグメンテーション違反でプログラムが死にます。必ず `iso_c_binding` の定数を使ってください。
3. デバッグの基本は「アドレス確認」:
もし計算がおかしいときは、`c_loc()` を使ってFortran変数のアドレスを確認し、C言語側のポインタ値と比較してください。一致していなければ、それは「マッピングの失敗」です。
—
まとめ:まずはここから
まずは小さなプログラムで、C言語側で確保した `malloc` 領域をFortranの配列に流し込み、値を書き換えてみてください。
Fortranは、古い言語だと思われがちですが、メモリの直叩きができる最強の「高速計算エンジン」です。この `C_F_POINTER` を使いこなせるようになれば、既存のC資産を活かしつつ、計算コアだけをFortranで爆速化させるという、エンジニアとしての強力な武器が手に入ります。
「計算が遅い」「メモリが足りない」と悩む夜からおさらばするために、ぜひ今日から導入してみてください。応援していますよ!

コメント