2

Fortran と関数/サブルーチン ポインターに問題があります。引数として配列を取る 2 つの関数があります。f1 では a(n,n)、f2 では a(n*n) です。サブルーチンを手動で呼び出すと、同じ配列でこれを行うことができます。

real :: a(5, 5)
call f1(a, 5)
call f2(a, 5)

しかし、ポインターを使用してこれを実行しようとすると、コンパイラーは次のエラーでそれをスローします。

ptr => f2
       1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank missmatch in argument 'a'

これを回避する方法はありますか?ポインターについて考えていましたが、同じ問題があり、作成するには次元数を知る必要があります。

参考までに、ここに完全なコードを示します (長すぎないことを願っています..)

program ptrtest
implicit none

interface
    subroutine fnc(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f1(a, n)
        integer :: n
        real :: a(n, n)
    end subroutine

    subroutine f2(a, n)
        integer :: n

        real :: a(n*n)
    end subroutine
end interface

procedure(fnc), pointer :: ptr => null()
real :: a(5, 5)
real :: b(4, 4)

ptr => f1

call ptr(a, 5)
write(*,*) a

!this one does not work..

!ptr => f2
!
!call ptr(b, 4)
!write(*,*) b

call f2(b, 4)
write(*,*) b
end program

subroutine f1(a, n)
integer :: n
real :: a(n, n)
integer :: i

a = 1
end subroutine

subroutine f2(a, n)
integer :: n
real :: a(n*n)

a = 2
end subroutine

これを行う方法があることを本当に願っています。配列の次元が毎回一致するように、すべてのサブルーチンを実際に書き直すことはできません:/

よろしく、カバ

4

4 に答える 4

2

編集:ポイントは、他の回答に書かれているように、実際の引数と仮引数が一致しないことです。私の提案を回避しようとするのではなく、引数が一致するように配列のランクを変換するポインターを作成することです。この手法は「ポインター境界の再マッピング」です ( fortran での配列の次元の変更も参照してください)。より完全な例を次に示します。

module my_subs

contains

subroutine f1 (array)

   real, dimension (:,:), intent (in) :: array
   write (*, *) "f1:", ubound (array, 1), ubound (array, 2)

end subroutine f1


subroutine f2 (array)

   real, dimension (:), intent (in) :: array
   write (*, *) "f2:", ubound (array, 1)

end subroutine f2

end module my_subs


program test_ranks

   use my_subs
   real, dimension (2,2), target :: a2d
   real, dimension (:), pointer :: a4

   a2d = reshape ( [1., 2., 3., 4.], [2,2] )
   call f1 (a2d)

   a4 (1:4) => a2d
   call f2 (a4)

end program test_ranks

インターフェイスを自動的に明示的にするためのサブルーチンがモジュールに含まれています。コンパイラが引数の一貫性の間違いを見つけられるようにするため、これが最も安全な方法であると考えています。コロン) を使用しました。

おそらく、この例はプロシージャへのポインタを使用していないため、質問のニーズを満たしていません。異なるランクの配列を期待するプロシージャに同じ配列を渡します。

于 2012-03-16T23:20:45.303 に答える
2

サンプル プログラムを明示的なインターフェイスの使用 (インターフェイス ブロックによる) から暗黙的なインターフェイスの使用 (インターフェイスに言及せずにプロシージャ宣言による) に変更すると、うまくいくように見えます。

インターフェイス ブロックを削除し、 の宣言を少し変更して、とのptrプロシージャ宣言を追加します。次のようにします。f1f2

procedure(), pointer :: ptr => null()
procedure() :: f1, f2

(または、 procedure ステートメントの代わりにexternalfor f1、 and 、ステートメントを使用することもできます。)f2

Fortran 90 以降で導入された機能の一部を実際のサブルーチンで使用する場合は、明示的なインターフェイスが必要になる可能性があるため、これが実際のプログラムでどの程度実現可能かはわかりません。

于 2012-03-16T23:51:06.187 に答える
2

1D (:) 配列を予期するサブルーチンに 2D 配列 (:,:) を渡しています。それが Fortran が不平を言う理由です。これを回避する 1 つの方法は、次のように、異なるランク配列を引数として取る同じ名前の複数の関数を持つモジュールを作成することです。

  module test 

  interface fnc1
      module procedure fnc1_1d, fnc1_2d
  end interface

  contains

  subroutine fnc1_1d(ar,b,ar_out)

  real :: ar(:), ar_out(:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_1d

  subroutine fnc1_2d(ar,b,ar_out)

  real :: ar(:,:), ar_out(:,:)
  integer :: b

  ar_out = ar*b

  end subroutine fnc1_2d

  end module test

fnc1 を呼び出すと、1 次元配列を渡す場合は fnc1_1d が呼び出され、2 次元配列を渡す場合は fnc_2d が呼び出されます。

Program modify_value

use test

implicit none

real :: a1(5), a1_out(5)
real :: a2(5,5), a2_out(5,5)
integer :: j

a1 = 1.
a2 = 2.

call fnc1(a1,4,a1_out)
call fnc1(a2,4,a2_out)

open(1,file="out.txt")

write(1,'(5F5.1)') a1_out
do j=1,5
    write(1,'(5F5.1)') a2_out(j,:)
end do


close(1)

End Program

out.txt現在は次のとおりです。

4.0 4.0 4.0 4.0 4.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

8.0 8.0 8.0 8.0 8.0

お役に立てれば。

于 2012-03-16T23:23:04.373 に答える
0

このセクションで:

サブルーチンf2(a、n)整数::n実数::a(n * n)

fortranがメインプログラムで2D配列を予期している場合は、1D配列を使用しています。

于 2012-03-16T23:33:11.283 に答える