gtool4/Fortran 90 library document

文字列の取り扱い

2001年06月16日 豊田英司


可変長文字列問題

Fortran の文字型は固定長文字列です。つまり、コンパイル時に長さの決まった文字列を扱います。しかしながら、実際の文字処理ではファイル名、変数名などのように長さが実行時にならないとわからない文字列を取り扱うケースが多くあります。このようなばあい、どのようにコーディングするのがよいのかについて議論します。

普通どうしているか

Fortran 組込の文字型

Fortran の立場では、文字型はひとつの型ではなく、長さというパラメタが異なる型たちの総称です。そのため文字型変数の長さはコンパイル時に決定してしまうのです。

長さの異なる文字型どうしの演算については以下のような規則があります。

したがって、文字列を取り扱う際には常に文字型変数の長さを十分大きくとるようにしておけば、文字型の値を代入しても Fortran 的には同値の(つまり a == b となるような)文字列が得られることは保証されます。しかし、同値性は失われないとはいっても、印字するときなどに文字列の末尾に余計な空白が何十文字〜何百文字も表示されるのは迷惑です。このような場合のために、TRIM 組みこみ関数を用いて末尾に空白を含まない最小限の文字列を得ることができるようになっています。

このようなアプローチによるコーディングの得失を下表にまとめます。

利点 欠点
  • 準備がいらない
  • 余計なアクセスルーチンなどが不要で効率がよい可能性が高い
  • 文字列長が短過ぎるとプログラムが入力によっては文字列末尾を切り捨ててしまう不具合を発生しやすい
  • プログラム単位ごとに文字長を指定しなくてはならないため、文字長を一貫して変更することが困難
  • プログラマが根拠もない文字長をハードコードすることがままあるため、品質保証が困難

ISO_VARYING_STRING モジュール

Fortran 90 (ISO 1539-1:1991) の導入後、補助規格 ISO 1539-2:1994 というものが制定され、任意の長さの文字列を表現できる type(VARYING_STRING) 型とそれにアクセスする手続の仕様を決めています。

利点 欠点
  • 扱える文字列の上限をサブルーチンごとに明示する必要がなく、仕様保証が容易になる
  • 実行時に変化する文字長を保持できる
  • 文字列を返す関数を作ったとき、結果に TRIM をかけなくても末尾の余計な空白がつかないためすぐに他の演算で使える

 

  • ほとんどの Fortran 処理系で実装されていないので自分で用意する必要がある
  • 規格のインターフェイスをコンパイルできないようなバグのある処理系がたくさんある
  • 規格が例示する実装は大抵メモリリークする
  • 比較演算子は組込み文字型と同じ動作で、末尾空白は結局無視されている

このようなアプローチでは、プログラマは扱う文字長の上限を明示する必要がありません。従って文字長の上限によってプログラムの動作に不自然な制約を課する必要がなくなります。また、プログラムの仕様変更に伴ってプログラムのあちこちを修正して回る危険もありません。このことはライブラリを自分でコンパイルしなければならない欠点を補ってあまりあるように思われます。

規格の付属書で例示された実装が「メモリリーク」する(ポインタ配列に allocate を行った後 deallocate しない)という問題は広く知られていますが、扱える文字長に上限を与える実装は禁止されていないので、固定長バッファを用いて一切 allocate を用いない実装によって、まがりなりにも規格に合致しながらメモリリークを起こさない実装を作ることができます。

注: 「まがりなりにも」というのは、処理系に扱えるプログラムの大きさあるいは複雑さに実装が上限を課することは規格上許されているため、固定長バッファを用いる実装をもって処理系とみなし、ある程度以上大きい文字列は扱えないのだと言い張れば規格合致処理系だという程度のことです。実用上は充分有益ですが、あまり誉められた話ではありません。なお、Fortran 95 準拠の新しい ISO 1539-2:1999 で例示されている ISO_VARYING_STRING モジュール実装例ではFortran 95 の構造体成分初期化機能を用いてメモリリーク問題が相当低減されています。唯一のメモリリークの可能性は VARYING_STRING 型を返す関数の結果を他の手続の引数として使用するときだけです。残念ながら、この問題だけは当面解消しない公算が大きいように思われます。

そこで、gtool4 ライブラリでは固定長バッファ方式で ISO_VARYING_STRING インターフェイスを実装してこれを内部処理で積極的に用いてきました。しかしながら、非常に残念なことに、ISO_VARYING_STRING インターフェイスには処理系のバグによる移植性の問題があることがわかってきました。

ほとんどすべての言語処理系にはバグがあるものです。そして、よくテストされていない機能にはほとんど使い物にならないほどのバグがあるものです。著者の身近な環境では、以下のような問題が発生しました(理由は推測)。

このような問題への対処としてインターフェイスを変える場合、 (ISO_VARYING_STRING が将来有望であったとすればなおさら)インターフェイスモジュールを同名にするのは混乱の元です。

gtool4 ではどうするか

そこで、現在次のような対策が検討されています。

より安全な DC_STRING インターフェイス

アプリケーションプログラムが十分な移植性を確保することはソースコードレベルで流通するソフトウェアに不可欠な条件です。コンパイルを行うユーザがシステム依存な修正を適切に行えるほど確実な知識と暇を兼ね備えなければならないという要求は理不尽なものだからです。

一方、ISO_VARYING_STRING インターフェイスが顕在化させた処理系のバグは、理由が推測できるようなものでした。そこで、以下のような対策によってライブラリを修正する事にします。

結局可変長文字列はいつ使うべきか

可変長文字列を使わなければならない目的として文字列末尾の空白を無視できない用途をあげるのはあまり現実的ではない。ISO_VARYING_STRING はそのために必要な比較演算子すら用意していないからである。してみると、可変長文字列型を用いる目的としては文字長をプログラム中にハードコードしないで済むということが最重要であると考えられる。このような見地から、以下のような指針をたてることができる。