1

データ収集ルーチンを一部のレガシー Fortran に追加しました。使いやすくするために、C でファイル i/o ルーチンを作成しました。

私はgccとgfortranを使用しています。

問題: C 関数への無害な呼び出しのように見える間に、いくつかの Fortran 変数名が上書きされています。

C 関数はすべて void 型、名前はすべて小文字、引数はすべてポインター、関数名はすべて末尾に「_」を含み、サブルーチンとして Fortran から呼び出されます。私は前にこれをやったことがあります。gfortran は、すべての Fortran シンボルを小文字に強制し、すべてのエントリ ポイントに「_」を追加して、同じ名前の C エントリ ポイントと区別します。

C ファイルの一部を次に示します。

#define MAXFILES 20
FILE *outfile[MAXFILES];

/* int2char_ generates a left zero padded string (*theChar) from an int
   (*theInt), that is *numChar characters long.  E.g, called from fortran:

   string *5 arun
   integer nrun
   integer nnchar

   nrun = 231
   nchar = 4
   call int2char (nrun, arun, nnchar)
c...   returns '0231' in arun
*/
void int2char_ (int *theInt, char *theChar, int *numChar) {

  int nchar;

  nchar = *numChar;

  if (nchar > 9) nchar = 9;
  if (nchar < 1) nchar = 1;

  sprintf(theChar, "%*.*d", nchar, nchar, *theInt);

  return;
}  // end of int2char


void openwrite_ (char *filename, int *unit) {
  outfile[*unit] = fopen (filename, "w");
  return;
}  /* end of openWrite */

void closefile_ (int *unit) {
  int closed;
  if (outfile[*unit]) {
    closed = fclose (outfile[*unit]);
  }
  return;
}

void writefirststr_ (char *string, int *unit) {
  int printed;
  printed = fprintf (outfile[*unit], "%s", string);
//  printed = fputs (string, outfile[*unit]);
  return;
}

踏まれる Fortran 変数の宣言は次のとおりです。

c...................
c"Display the mass matrix when DISMAT is set TRUE "
      LOGICAL, save :: DISMAT
c...................

注: 私は元々volatile、修飾子の代わりに宣言修飾子を使用していましたsave。変わりはない。

呼び出しは次のとおりです。

c...................
c...  build file name
          numchar = 4
          call int2char (nrun, filenumber, numchar)
          begin = 1
          end = len_trim(fileprefix)
          filename(begin:end) = fileprefix

          begin = end + 1
          end = begin + 3
          filename(begin:end) = filenumber

          begin = end + 1
          end = begin + 3
          filename(begin:end) = fileext

          begin = end + 1
          filename(begin:begin) = char(0)


c...  close open file
          call closefile (lunit)

c...  open file
          call openWrite (filename, lunit)

c...  write header(s)
          call writeFirstStr (atime', lunit)
c...................

行を実行すると問題が発生しcall writefirstStr ('time', lunit)ます。

atime'time' にデータ化されcharacter*5、明示的に null で終了する ですtime(5:) = char(0)。ステップスルーしwritefirststr_()ても問題はなく、正しい情報がファイルに書き込まれます。

の後に (gdb 経由で) return ステートメント (上記のコード フラグメントを含む fortran ルーチン内) にジャンプしてもcall openWrite (filename, lunit)、問題はありません。

r を呼び出すwriteFirstStと、fortran 変数が上書きされますDISMATDISMATまた、上記の C 言語呼び出しを行うルーチンには含まれていないことにも注意してください。

私がまだ試していないのはsave、すべての Fortran 変数で修飾子を使用することです。レガシー コードの量による論理的な問題です。

誰にも考えはありますか?

4

2 に答える 2

0

あなたのコードにはいくつかの問題があると思います:

sprintf(theChar, "%*.*d", nchar, nchar, *theInt);

Integer の精度として渡すことができる整数は 1 つだけなので、書式文字列は "%*d" にする必要があります。

次の問題は、文書化されていない Fortran の「機能」です。Fortran は、文字列のサイズをすべての変数の最後に隠し引数として渡します (今回はポインターではなく値で渡します)。

関数は次のようになります。

void int2char_ (int *theInt, char *theChar, int *numChar, long len_of_the_char);
void writefirststr_ (char *string, int *unit, long len_of_string);

長さ変数の順序は、文字列が渡される順序と同じです。長さ変数のデータ型は、コンパイラと OS によって異なります。Fortran 90 と明示的なインターフェイスに注意してください。明示的なインターフェースがこの追加の引数を抑制する可能性があります。

ユニットを開かずに閉じようとすると、次の問題が発生する可能性があります。グローバル配列を初期化しません(またはコードを投稿しませんでした;-))

このエントリの残りを削除しました (Vladimir F に感謝)。

于 2014-02-24T19:10:51.957 に答える