【入門編】ISO_C_BINDINGにおける配列の受け渡しと形状の不一致対策 – モダンFortran言語仕様と実践実践マスター

FortranとCの深淵なる握手:`ISO_C_BINDING`で配列のメモリを統べる

こんにちは!元・宇宙航空研究開発の現場で、スパコンの計算ノードと数十年格闘してきた者です。

これからFortranの世界へ飛び込もうとしている皆さん、ようこそ。CやPythonを触ってきた方にとって、Fortranの配列は「魔法の箱」のように見えるかもしれません。しかし、その箱の裏側には「メモリ連続性」という絶対の掟が隠されています。

今回は、C言語とFortranをシームレスにつなぐための最強の武器、`ISO_C_BINDING`モジュールを使った配列受け渡しの極意を伝授します。ここを理解すれば、あなたの計算プログラムは一気に「プロの現場レベル」へ昇華しますよ。

なぜ「そのまま」ではいけないのか?

C言語とFortranの最大の溝は、配列の持ち方(ディスクリプタ)にあります。

  • C言語: メモリ上のただの「ポインタ」。どこから始まって、どこで終わるかは、プログラマが手動で管理します。
  • Fortran: 「配列記述子(Descriptor)」というメタデータを持っています。形状、次元、ストライド(飛び幅)、そしてメモリの開始位置までをパッケージ化した、非常にリッチな構造体なのです。

この「リッチな記述子」を、C言語の「ただのポインタ」にどう翻訳するか。これが、我々数値計算屋が日々頭を悩ませてきた最大の課題です。

ステップ1:`ISO_C_BINDING`で「共通言語」を話す

まずは、Fortran側で「この変数はCとやり取りするぞ!」と明示します。`use, intrinsic :: iso_c_binding` を使うのが作法です。

subroutine process_array(c_ptr, n) bind(c, name=”process_array_c”)
use, intrinsic :: iso_c_binding
implicit none

! C言語から渡されたポインタを、Fortranの配列として再構築します
type(c_ptr), value :: c_ptr
integer(c_int), value :: n

! ここで「ポインタを配列にマップ」する魔法を使います
real(c_double), pointer :: f_array(:)

! c_f_pointerが、Cのポインタ(c_ptr)をFortranの形状(f_array)に変換するブリッジです
call c_f_pointer(c_ptr, f_array, [n])

! これで f_array をFortranの高速な配列演算で扱えるようになります!
f_array = f_array 2.0_c_double
end subroutine

ステップ2:メモリの連続性を守る(ここが重要!)

現場でよくある失敗は、Fortran側で「スライス(`a(1:n:2)`のような飛び越し)」をした状態でCに渡そうとすることです。

Fortranの配列は列優先(Column-major)ですが、Cは行優先(Row-major)です。さらに、スライスを行うとメモリが連続しなくなり、C側からは「わけのわからないデータ構造」に見えてしまいます。

鉄則:Cに渡す配列は、必ず`contiguous`(連続)属性をつけましょう。

subroutine work_with_data(arr)
! この属性をつけることで、コンパイラは「連続したメモリブロック」であることを保証し、
! C言語側でも安全にポインタ演算が行えるようになります。
real(c_double), target, contiguous :: arr(:)
! …
end subroutine

最適化の極意:コンパイルフラグの魔法

コードが書けたら、コンパイラを正しく調教しましょう。例えば、Intel Fortran (ifort/ifx) を使う場合、以下のようなフラグが現場の標準です。

最適化と、メモリレイアウトの厳密なチェック
ifort -O3 -xHost -qopenmp -assume contiguous_assumed_shape -c my_code.f90

特に `-assume contiguous_assumed_shape` は、配列の形状を仮定する際に連続性を前提とする設定です。これをONにするだけで、コンパイラは「わざわざ一時的なコピーを作らずに計算する」という大胆な判断をしてくれるようになり、実行速度が数%〜数十%跳ね上がることも珍しくありません。

若手エンジニアへのアドバイス

「なぜこんなに面倒なことを?」と思うかもしれません。しかし、宇宙の軌道計算や流体シミュレーションにおいて、この「メモリの1バイト」へのこだわりが、解析完了までの時間を数日単位で短縮します。

1. Cとつなぐときは`c_f_pointer`を通す。
2. `contiguous`属性でメモリの連続性を守る。
3. コンパイラの最適化フラグを味方につける。

この3つを守るだけで、あなたの書くFortranコードは、世界中のどんなスパコンでも高速に動く「信頼できる計算基盤」になります。

最初は少し難しく感じるかもしれませんが、一度この仕組みを掌握してしまえば、他のどの言語よりも強力な武器になるはずです。何か詰まったら、またいつでも聞いてくださいね。皆さんの研究が、素晴らしい成果につながることを応援しています!

コメント

タイトルとURLをコピーしました