導入
数値計算の現場では、高速な計算処理をFortranで記述し、フロントエンドや制御ロジックをC/C++で実装するという構成がよく見られます。しかし、異なる言語間で「文字列」をやり取りする際、予期せぬセグメンテーションフォールト(メモリエラー)に悩まされた経験はありませんか?その原因の多くは、Fortran特有の「隠し引数(Hidden Length)」の仕様にあります。今回は、この歴史的背景と正しい解決策を解説します。
基礎知識
Fortran 77をはじめとする古い仕様では、文字列型の引数は「文字列の開始アドレス」と「文字列の長さ」の二つがセットになって関数に渡されます。C言語の場合、文字列はヌル終端(’\0’)で長さを判断しますが、Fortranは「固定長」を前提としているため、関数呼び出しの裏側で、文字列の長さを示す整数値が自動的に「隠し引数」としてスタックやレジスタに積まれます。C言語側からこの隠し引数を渡さずに呼び出すと、Fortran側がメモリ上の不正な領域を長さ情報と誤認し、深刻なメモリアクセス違反を引き起こすのです。
実装/解決策
この問題を解決するには、C言語側から呼び出す際に、Fortran側の規約に合わせて「文字列の長さ」を引数の最後に追加で渡す必要があります。現代のコンパイラ(gfortranなど)を利用する場合、明示的にこの挙動を考慮したインターフェース設計を行うのが鉄則です。
サンプルプログラム
以下は、C言語からFortranの文字列処理ルーチンを呼び出す際の正しい実装例です。
/ Fortran側で定義された関数: SUBROUTINE PRINT_STR(S) /
/ C言語から呼び出す際は、長さ情報を引数の最後に追加する /
include
/ Fortranのサブルーチン名を宣言(環境によりアンダースコアが必要な場合あり) /
extern void print_str_(char s, int len);
int main() {
char message = “Hello, Fortran!”;
/ 文字列の長さを算出(ヌル文字は含めない) /
int len = 15;
/ Fortran側は引数(文字列アドレス, 長さ)の順で期待している /
print_str_(message, len);
return 0;
}
/
注意: Fortran側で受け取る際は以下のように記述します
SUBROUTINE PRINT_STR(S)
CHARACTER() S
PRINT , S
END
/
応用・注意点
この隠し引数の扱いは、コンパイラやOSの呼び出し規約(ABI)によって微妙に異なります。
1. コンパイラのオプション: -fno-second-underscore などのフラグ設定で、シンボル名の解決ルールが変わることがあります。
2. C言語のヌル終端: Fortran側で渡された文字列を扱う際、Fortranはヌル終端を認識しないため、文字列操作を行う際は境界チェックを厳重に行う必要があります。
3. 現代的な回避策: 可能であれば、ISO_C_BINDINGモジュールを使用してFortran側でC言語互換のインターフェースを定義することを強く推奨します。これにより、隠し引数問題を根本から回避でき、コードの移植性が大幅に向上します。
既存のレガシーコードを改修する際は、まず呼び出し先の実装を確認し、スタックの状態が整合しているかを確認することから始めてみてください。

コメント