在Fortran 90中传递参数的聪明方法

时间:2011-08-03 19:43:08

标签: fortran argument-passing subroutine fortran90

我是Fortran新手。我正在尝试编写一个子程序,它将从主程序中获取四个参数,然后向主程序输出一个涉及最初传入的四个参数的数组。这样做的好/聪明方法是什么? / p>

例如,在我的测试程序中,我在主程序中创建了四个实变量(abcd)。然后我将这些实变量传递给一个名为mysub的子程序。我希望mysub能够接收abcd,使用它们填充2 x 2阵列调用o,然后将o发送到主程序以显示(和可能的修改)。所以,我尝试了以下内容:

SUBROUTINE mysub(w,x,y,z)
  IMPLICIT NONE
  REAL, INTENT(IN) :: w, x, y, z
  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o

  ALLOCATE(o(2,2))
  o(1,1)=w
  o(1,2)=x
  o(2,1)=y
  o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4

  CALL mysub(a, b, c, d)

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
END PROGRAM test

但是,我收到以下错误:

test.f90:10.53:

  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o
                                                     1
Error: Symbol at (1) is not a DUMMY variable

我将其解释为,编译器不知道o是什么,因为o不在子例程头中的参数列表中:SUBROUTINE mysub(w,x,y,z)。所以我可能需要在该标题中包含o。所以,我接下来尝试以下内容(我使用!...表示更改或添加):

SUBROUTINE mysub(w,x,y,z,o) !...
  IMPLICIT NONE
  REAL, INTENT(IN) :: w, x, y, z
  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o

  ALLOCATE(o(2,2))
  o(1,1)=w
  o(1,2)=x
  o(2,1)=y
  o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4
  REAL, DIMENSION(:,:), ALLOCATABLE :: o !...

  CALL mysub(a, b, c, d, o) !...

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
  DEALLOCATE(o) !...
END PROGRAM test

这似乎工作正常,我得到了正确的输出:

   1.1000000       2.2000000
   3.3000000       4.4000001

但是,我的问题是,这是一个很好的方法吗?在这个工作示例中,我在主程序的子例程中声明了数组o 两者。这似乎有点令人困惑,因为我认为这意味着我需要注意 子程序主程序分配o(但我认为,不是,以避免错误消息)。有没有更聪明的方法 - 从子程序发送数组到主程序?谢谢你的时间。

3 个答案:

答案 0 :(得分:3)

你的解决方案,使“o”成为一个意图(out)论证就好了。如果没有“o”作为参数,则子程序中的变量“o”与主程序中的变量“o”之间没有关联,因此主程序中没有声明或分配。另一个解决方案(除了@ ja72提供的解决方案之外)将改变你的方法:使“o”成为子程序的一个intent(inout)参数并将其分配给主程序。可能的优点:分配和解除分配在代码中更加紧密,并且配对。可能的缺点:取决于程序逻辑和设计,子程序可能最熟悉数组维度。

P.S。如果在主程序中分配数组,并且实际上不在子例程中使用数组的可分配属性(即,您不分配或取消分配它),那么您不必使用allocatable属性声明它在子程序中 - 一个有用的简化。在这种情况下,“意图(外出)”可能是合适的。但是如果你在主程序中分配数组并希望将该状态传递给子程序,那么参数状态不能是“intent(out)”。 “intent(out)”在进入程序时自动解除参数。

答案 1 :(得分:1)

如果你想返回一个数组,你可以a)将它添加到INTENT(OUT)的参数,就像你的例子#2一样,在sub中分配,或者b)创建一个函数并在外部分配数组:

FUNCTION myfun(w,x,y,z,n,m)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n,m
REAL, DIMENSION(n,m) :: myfun
REAL, INTENT(IN) :: w,x,y,z

  myfun(1,1)=w
  myfun(1,2)=x
  myfun(2,1)=y
  myfun(2,2)=z

END FUNCTION
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4
  REAL, DIMENSION(:,:), ALLOCATABLE :: o !...

  ALLOCATE(o(2,2))
  o  = myfun(a,b,c,d,2,2)

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
  DEALLOCATE(o) !...
END PROGRAM test

实际上我认为你的解决方案更清洁。

答案 2 :(得分:1)

从您的问题中不清楚您是否事先知道数组的大小,但如果您这样做,通常在同一个地方分配和释放数组通常是一个好习惯,或者更好的是让编译器在可能的情况下分配内存。

我该怎么做:

  • 如果在编译时已知大小: 在主程序中声明您的数组,在子例程中使用intent(out)

  • 如果仅在运行时知道大小: 在主程序中分配,在子程序中使用intent(out)并在主程序中取消分配。

功能最适合小输出,因为需要复制输出。