2016-08-08 2 views
0

私の質問をすばやく提示するための簡単なデモンストレーションコードを記述します。ここにコードがありますが、これはうまく構築できません。select case structure内で引数を宣言する

main.f90の

PROGRAM test 
IMPLICIT NONE 

    INTEGER :: a 
    a = 1 
    CALL sub(a) 

END PROGRAM 

sub.f90

SUBROUTINE sub(a) 
IMPLICIT NONE 

    INTEGER :: a 
    SELECT CASE(a) 
     CASE(1) 
      INTEGER  :: b,c 
      b = a 
      c = a*2 
     CASE(2) 
      INTEGER  :: b(4),c(4) 
      b(:) = a 
      c(:) = a*2 
    END SELECT 

END SUBROUTINE 

私がコンパイルしようとしましたが、エラーショー '予期しないデータ宣言文は、' サブルーチンファイルで発生します。 SELECT CASE構造体内で引数型を宣言できないということですか?問題は、メインプログラムでaの値を定義し、サブルーチンsub(a)に渡したいということです。引数の型bとcはaで決める必要があるため、事前に決定することはできません。私はまた、bとcの値をメインプログラムに戻したいと思います。私はそれをどうやって行うのか分かりません。だから私はこれをどのように達成できますか?ありがとう。

+0

を持っていますか?もしそうなら、 'block'構造を使うことができます。 – jlokimlin

+0

ありがとうございます。私は実際にFortran 90を使用してプログラムにいくつかの変更を加えようとしているので、潜在的なトラブルを防ぐためにそれをそのままにしておきたいかもしれません。 – Ruizhi

+0

私はあなたの位置を理解していません。削除された機能を使用していない標準準拠のFortran 90プログラム(すでに廃止されたと宣言されているため、ほとんど使用されていない)は、Fortran 2015に準拠しています。Fortran 90は30年以上前であり、現代のプログラミング慣行。どのコンパイラを使用していますか? – jlokimlin

答えて

2

あなたが知っているとおり、あなたが書いたコードは違法です。今や、一部の人々はBLOCKの2008年の機能を指摘しており、それが必要なものなら、それを試すことができます。しかし、私はあなたがこれで何をしたいかについてもっと学びたいと思っています。

あなたが同じ名前を付けるという事実は、後で同じ方法でそれらを扱いたいということを私に示唆しています。それは物事を本当にトリッキーにします。今、あなたはbcがあることを覚えておく必要があり

integer, dimension(:), allocatable :: b, c 
select case(a) 
    case(1) 
     allocate(b(1), c(1)) 
    case(2) 
     allocate(b(4), c(4)) 
end select 
b = a 
c = 2 * b 

1)を使用し、別の変数:

INTEGER :: b_scalar, c_scalar, b_array(4), c_array(4) 
select case(a) 
    case(1) 
     b_scalar = a 
     c_scalar = 2*b_scalar 
    case(2) 
     b_array = a 
     c_array = 2*b_array 
end select 

2)を使用し割付け配列ここで

は、いくつかの選択肢です配列、おそらくは長さが1です。あなたはそれらをそのように扱わなければなりません。

これらのすべてには長所と短所があります。あなたがしていることをやっている理由を知らずに、私はあなたに最善のアドバイスをする方法を本当に知らない。

あなたの2番目の質問について:返す簡単な方法は、INTENT(OUT)仮引数です。ここでは作業例です:

module mod_allocatable 
contains 
    subroutine my_sub(a, b, c) 
     implicit none 
     integer, intent(in) :: a 
     integer, dimension(:), allocatable, intent(out) :: b, c 
     if (allocated(b)) deallocate(b) 
     if (allocated(c)) deallocate(c) 
     select case(a) 
      case(1) 
       allocate(b(1), c(1)) 
      case(2) 
       allocate(b(4), c(4)) 
     end select 
     b = a 
     c = 2 * b 
     end subroutine my_sub 
end module mod_allocatable 

program test_alloc 
    use mod_allocatable 
    implicit none 
    integer :: a 
    integer, allocatable, dimension(:) :: b, c 
    a = 1 
    call my_sub(a, b, c) 
    print *, "b is ", b 
    print *, "c is ", c 
end program test_alloc 
+1

'b'と' c'は 'intent(out)'であるため、割り当てステータスのテストは冗長です。 – francescalus

+0

ありがとう、@francescalus。私はいつも何とか準備をしようとします。それが本当に冗長であれば、私はコンパイラがそれを取り除くことを期待しています。 – chw21

+0

@ chw21お返事ありがとうございました。スカラーとベクタの両方でbとcの名前を保持したいのは、それらを別のインタフェースの入力のオーバーロードとして使用したいからです。オーバーロードプロシージャは、入力タイプを識別することによって自動的にサブルーチンを選択します。このようにして、可変数とサブルーチン数を最小に保つことができます。 – Ruizhi

3

実際には、構造ローカル変数を宣言する方法ではなく、サブルーチンからスカラーまたは配列を返す方法を実際に求めています。その場合、2つの別々のサブルーチンを使用することを検討してください。スカラーのための1つのバージョンと配列のための1つのバージョン。必要に応じて、1つの名前で汎用プロシージャーとしてオーバーロードすることができます。

ELEMENTALについても考えていますが、スカラーaを使用すると、配列では機能しません。


あなたはまだローカル変数を宣言する方法を知りたい場合は、次の

変数のみ手続きの開始時に、ブロックの先頭で宣言することができます。これは、最近のバージョンの最も一般的なコンパイラ(PCコンパイラ、少なくともGNUとIntel)からサポートされているFortran 2008の機能です。

SELECT CASE(a) 
    CASE(1) 
     BLOCK 
      INTEGER  :: b,c 
      b = a 
      c = a*2 
     END BLOCK 
+0

興味深い。しかし、これらの宣言された変数は、 'BLOCK'ステートメントの終わりまで生き残っていますか?私はそうは思わない。 – chw21

+1

@ chw21もちろん、そうではありません。そして、もしOPが示唆していた構文が存在しても、それらは生き残ることはできないでしょう。 –

+1

bおよびcは、b =およびc =の場合、またはSAVEが添付されている場合に保存されます。 – Holmz

0

これは過度にエレガントではありません...あなたは、現代のFortran(2008+)コンパイラへのアクセスを

SUBROUTINE sub(a) 
    IMPLICIT NONE 

    INTEGER,    INTENT(IN) :: a 
    INTEGER, DIMENSION(:), ALLOCATABLE :: b, c 

    SELECT CASE(a) 
     CASE(1) 
      IF(ALLOCATED(B)) THEN 
       IF(UBOUND(B)) .NE. 1) THEN 
       DEALLOCATE(B) 
       ALLOCATE(B(1)) 
       ENDIF 
      ELSE 
       ALLOCATE(B(1)) 
      ENDIF 

      IF(ALLOCATED(C)) THEN 
       IF(UBOUND(C)) .NE. 1) THEN 
       DEALLOCATE(c) 
       ALLOCATE(C(1)) 
       ENDIF 
      ELSE 
       ALLOCATE(C(1)) 
      ENDIF 

      b = a 
      c = a*2 
     CASE(2) 
      IF(ALLOCATED(B)) THEN 
       IF(UBOUND(B)) .NE. 4) THEN 
       DEALLOCATE(B) 
       ALLOCATE(B(4)) 
       ENDIF 
      ELSE 
       ALLOCATE(B(4)) 
      ENDIF 

      IF(ALLOCATED(C)) THEN 
       IF(UBOUND(C)) .NE. 4) THEN 
       DEALLOCATE(C) 
       ALLOCATE(C(4)) 
       ENDIF 
      ELSE 
       ALLOCATE(C(4)) 
      ENDIF 

      b(:) = a 
      c(:) = a*2 
     CASE(DEFAULT) 
      WRITE(*,*)'how did we get here?... a=',a 
    END SELECT 

END SUBROUTINE Sub 
+0

はい - bとc(aとbから)を読み込むように固定した場合。 そしてchw21は私がキーを突きつけている間に非常に似たアプローチで突っ込んだ。 – Holmz

+1

実際にchw21の答えは興味深い点を挙げています。 INTENTはBとCのINOUTである必要があるかもしれません。私は、UBOUNDがINまたはINOUTを持つINTENTなしでBの境界が何であるかを知らないことを知っています。あなたがそれが基本的にOUTであることを知っているときは直感的なカウンターカウンターですが、明白ではないもののためにINが必要です。 – Holmz

+0

私はあなたの最終的なコメントを理解していません。 'b'と' c'は仮引数ではありません(意図はありません)。これは、 'b'と' c'が割り当てられていない事例構築の開始時に( 'save'dされていないので)決して実行されない条件付き部分の塊を与えることを意味します。 – francescalus

関連する問題