LoginSignup
0
0

More than 3 years have passed since last update.

処理系依存のstatus='unknown'はデンジャー

Last updated at Posted at 2020-06-21

はじめに

f90ファイルでopen文を書く際に,これまではあまり深く考えずにstatus='unknown'を使っていたが,罠にハマったので記録しておく.結論としてはunknownはできるだけ使わずに,statusは明示(new, old, replace)するべき.

2020/06/23 コメントを受けての追記:以下の「罠」はunknown+streamの組み合わせとしては仕様通りの振る舞いを示していると思われる.ただし,結論は変わらない.

次のようなバイナリ形式のファイル出力を行う.ちなみにform='unformatted',access='stream'form='binary'は同義であるが,後者はgfortranでコンパイルできない(Fortran でのバイナリ (unformatted, binary) の扱いについてのメモ).

test.f90
program unknown_test
    use,intrinsic :: iso_fortran_env
    implicit none
    integer(int32) unit_no

    open(newunit=unit_no,file='my_name_is_unknown.dat',form='unformatted',access='stream',status='unknown')
    write(unit_no) 'my name is unknown.'
    write(unit_no) 1,2,3,4,5,6 !<-あとで増やす(本文参照)
    close(unit_no)

end program unknown_test

実行環境はWindows 10でWSL(Ubuntu)でGNUコンパイル

$ gfortran -v
...
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
$ gfortran test.f90 && ./a.out && ls -l my_name_is_unknown.dat
-rw-rw-rw- 1 hoge hoge 43 Jun 21 12:42 my_name_is_unknown.dat

平和.43バイトのmy_name_is_unknown.datファイルが出力される.続いて,test.f90で!<-あとで増やすとしてマークしていた行を複製して数値データを増やしたmy_name_is_unknown.datを出力する.

$ gfortran test.f90 && ./a.out && ls -l my_name_is_unknown.dat
-rw-rw-rw- 1 hoge hoge 67 Jun 21 12:46 my_name_is_unknown.dat

まだ平和.ファイルサイズが67バイトに増加している.当然である.続いて,複製した行を削除して元の43バイトファイルが出力されるようにしてみる.

$ gfortran test.f90 && ./a.out && ls -l my_name_is_unknown.dat
-rw-rw-rw- 1 hoge hoge 67 Jun 21 12:47 my_name_is_unknown.dat

...ん?67バイト?......戦争である.

どうしてこうなった

2020/06/23 コメントを受けての追記:ファイルがすでに存在する時点でunknownで同名ファイルを出力すると,レコード長を指定しない限り(pos=***なし)は頭から上書きされていき,streamはEOFを書き出さないため,前回の残り滓がファイル端に残ることになる.

以下,引用→NAG Fortran コンパイラ 5.2 マニュアル

書式なしの順アクセスファイルとは異なり、書式なしストリームファイルに対し ファイル終端より前の位置に書き込む場合にはファイルの切詰めは行われない 点に注意して下さい。(しかし書式付きストリームの場合にはこの切詰めが行わ れます。)

2020/06/23 追記ここまで.

正直分からない.いや,処理系依存のunknownが悪さをしていることは色々と試すと分かったのだが,どう悪いことをしているのかまでは分からない.

「hexdump for VSCode」(バイナリデータを読むのに便利な VSCode の拡張機能「hexdump for VSCode」の紹介)を使って中身を見てみたが,どうやらバイナリデータが増える方向にはunknown処理が上書きとして働き,減る方向には上書き処理がキャンセルされているっぽくて,中身が変わっていない.でもファイル時間は更新されているしな...分からん.

ちなみに

  • 上記テストでは中身が変わっていなかったが,同様にしてParaView(可視化用オープンソースプログラム)用にVTKファイルを作成したところ,最終形態(なぜかファイルサイズが変わらない版)をParaViewで開くとフリーズする
  • form='formatted'つまりASCII形式で出力すると問題なく上書きされる

対処方法

冒頭に書いたように,処理系依存のunknownではなく,statusは明示(new, old, replace)するべき.たとえば上記テストの場合はreplace

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0