4

このコードが予期しない動作をすることがわかりました

module testmodule
   integer, parameter :: LCHARS = 50
contains
   subroutine init()
      call foobar("foobar")
   end subroutine

   subroutine foobar(s)
      character(len=*), intent(in) :: s
      call bar(s)
   end subroutine

   subroutine bar(str)
      character(len=LCHARS), intent(in)  :: str

      print *, str
   end subroutine
end module

program foo
   use testmodule
   call init()
end program

このコードは、コンパイラに依存するガベージを出力します。

問題は、文字列引数を使用してルーチンをジャンプしているという事実でありlen=*、文字列引数に指定された長さのルーチンに渡されます。

フードの下で正確に何が起こっているのですか? また、この動作は標準のどこに記述されていますか? 文字ルーチンの引数の長さを指定しないようにする必要がありますか?

4

3 に答える 3

5

あなたのコードは不適合だと思います。12.4.1.1Fortran 95 標準のセクションには、次のように記載されています。

12.4.1.1 仮データ オブジェクトに関連付けられた実引数
[...]
スカラー仮引数がデフォルト文字型の場合、仮引数の長さlenは実引数の長さ以下でなければなりません。仮引数は、実引数の左端のlen文字に関連付けられます。

于 2012-01-17T13:19:56.367 に答える
3

問題はbar、長さ50の文字列(を参照character(len=LCHARS), intent(in) :: str)が必要なのに対し、渡す文字列は長さ6のみであるということです。

ifort -Warn all、nodec、interfaces、declarations -gen_interfaces -check all -std test.f90

エラーが発生します

forrtl:severe(408):fort:(18):ダミー文字変数'STR'の長さは50で、実際の変数の長さ6よりも長くなっています。

知る限り、すべてのFortran引数は参照によって渡されます。舞台裏では、関数barが取得するのは、文字列の先頭へのポインタと、str値が文字列の長さである追加のパラメータです。したがってbar、の先頭から50文字分のメモリを使用し、strそれを画面に出力します。渡す文字列の長さはわずか6文字なので、残りの44文字は、「foobar」の後のメモリの次のビットにあるものになります。これは、実行時または使用するコンパイラによって異なります。

于 2012-01-17T12:55:46.900 に答える
2

標準の要件が満たされている限り、引数の受け渡しはコンパイラに依存しますが、一般に、CHARACTER(len=*) 仮引数には次のようなインターフェイスがあります。

void foo(char *s, int len)

また、foo プロシージャの実装では、非表示の len 引数が文字列の長さとして使用されます。OTOH、CHARACTER(len=somevalue) 引数の場合、非表示の len 引数は無視されるか、まったく渡されず、プロシージャのコードは somevalue が文字列の正しい長さであると想定します。

これまで見てきたように、自分が何をしているのかを本当に理解し、標準の章と節を引用して理由を説明できる場合を除き、LEN=* 以外は決して使用しないでください。

于 2012-01-17T13:00:58.973 に答える