1. 導入:なぜこの知識が重要か
数値計算の現場では、レガシーなFortran資産をCやC++から呼び出す機会が依然として多く存在します。その際、最も頻繁に発生し、かつ原因特定が困難なバグの一つが「文字列の引数」に関連するものです。Fortran 77の仕様では、文字列を渡すとコンパイラが自動的にその長さを隠し引数として付与します。この仕様を知らずにCから呼び出すと、スタック領域が破壊され、セグメンテーションフォールトや不可解な数値計算エラーを引き起こします。本稿では、この「死の谷」を回避するための実装技術を解説します。
2. 基礎知識:Fortranの文字引数の仕組み
Fortran 77の規格では、文字型変数(CHARACTER型)は、実体としてのメモリ領域と、その長さを保持する整数型の情報(隠し引数)のペアで管理されます。
C言語からFortranサブルーチンを呼び出す場合、コンパイラは引数リストの末尾に、文字列の長さを表す「size_t」または「int」を自動的に追加します。例えば、引数として文字列を1つ渡す場合、C側では「文字列のポインタ」と「文字列の長さ」の2つを渡さなければなりません。この隠し引数を渡し忘れると、関数の呼び出し規約(ABI)が崩れ、スタック上のアドレスがずれてしまいます。
3. 実装/解決策
CからFortranを呼び出す際は、必ず文字列引数の直後にその長さを追加するように設計します。コンパイラやOSによって隠し引数の型(intかsize_tか)や配置順序が異なる場合がありますが、一般的なLinux環境(GCC系)では、文字列の直後に引数リストの最後尾として長さを渡すのが通例です。
4. サンプルプログラム
以下の例は、C言語からFortranの文字列受け取りサブルーチンを正しく呼び出すコードです。
include
include
/ Fortranサブルーチンの外部宣言 (アンダースコアはコンパイラに依存) /
extern void print_str_(char msg, int len);
int main() {
char message = “Hello from C to Fortran”;
/ 文字列の長さを算出 /
int len = (int)strlen(message);
/ 第1引数に文字列ポインタ、第2引数に隠し引数である長さを渡す /
print_str_(message, len);
return 0;
}
5. 応用・注意点:現場でのトラブル回避
1. コンパイラによる差異:
使用するコンパイラやOS環境により、隠し引数の型が「int」ではなく「long」や「size_t」である場合があります。また、C++から呼び出す際は「extern “C”」を必ず指定してください。
2. 文字列の埋め込み:
Fortran側で「CHARACTER()」として受け取る場合、長さ情報が正確に渡されないと、文字列の末尾が正しく認識されず、ゴミデータが表示されることがあります。
3. モダンな回避策:
もしプロジェクトの規約で許されるのであれば、Fortran 2003規格で導入された「ISO_C_BINDING」を使用することを強く推奨します。これを使えば、Cの文字列を「char型の配列(またはポインタ)」として安全にやり取りでき、隠し引数を意識する必要がなくなります。レガシーコードの改修が難しい場合のみ、上記の手法を用いてスタックの整合性を厳密に守るようにしてください。

コメント