如果我将已分配的数组传递给具有不匹配维度的子例程,如何让Fortran警告我?

时间:2014-04-11 13:34:20

标签: fortran

我花了太多时间解决程序中的错误。我将子程序(让我们的调用mysub)定义为:

subroutine mysub(hourval,dayval,some,more,args)
use globals
implicit none

real:: hourval(24,ncol,nrow)
real:: dayval(ncol,nrow)

...
end

其中hourvaldayval是包含子例程中计算输出的数组,nrowncol是整数。

对子程序的调用类似于

call mysub(daygrid,hourgrid,some,more,args)

其中daygridhourgrid是之前为allocate d的数组。 hourgrid有3个维度(24,ncol,nrow),而daygrid有2个维度(ncol,nrow)。直到现在提到的所有变量(hourgriddaygridnrowncol)都在模块globals中声明。

我一直得到奇怪的结果,最后注意到我在子程序调用中切换了hourgriddaygrid的顺序,并且更改这解决了我的问题(程序中的实际变量名称不太明确) ,这使得错误有点难以发现)。但是,程序将正常编译,我不会在日志文件中收到任何相关的错误消息。

因此,我想知道是否有一种方法可以在编译时或运行时获取消息,指向该错误。我在Linux上使用英特尔Fortran 11.1,带有以下编译器标志:

-O3 -C -pg -traceback -g

我实际上依靠-C标志(相当于-check all)来检测这种错误,因为它意味着选项-check bounds。还有什么我可以做的吗?

3 个答案:

答案 0 :(得分:6)

您可能希望使用假定的形状伪参数来捕获这样的错误(即real, dimension(:,:) :: dayvalreal, dimension(:,:,:) :: hourval。)

来自现代Fortran解释由Metcalf,Cohen和Reid(2011):

  

假设伪参数形状时,不会发生形状或字符不一致。

此外,它并没有让我感到最惊人的编码风格,即通过use语句传递已经可用的变量作为同一子程序的实际参数。

答案 1 :(得分:3)

如果数组大小是"已知&#34>,编译器可能会在编译时注意到这一点。那时候。您的管理方式取决于您的代码。

如果有一个(显式或隐式)接口可用,ifort应该为你做这件事。

即使没有界面,您也可以对编译选项-warn interface感到高兴:这实际上比通常更好地检查界面是什么"显而易见"即使不是"可用"。 [我希望有人可以更好地解释。]

可能值得注意的是,除非接口出现故障,否则排名的数量不一定是个问题。相反,它归结为存储范围。在你的情况下,存储是完全不同的。[1]

回应你的评论,关于接口。

您已经在使用模块,因此如果mysub位于呼叫主机的(其他)模块use中,则可以使用显式接口。这是一件好事。可以在界面说明的SO上找到许多细节。

最后,我要说即使hourgriddaygrid在模块中声明,这些名称的伪参数也是不同的东西。

编辑,更明确。

[1]解决尺寸"不匹配问题"通常是一个更难的问题。 Fortran 2008标准在第12.5.2.11节中说明了子程序声明(我的重点)

  

如果伪参数是显式形状或假定大小的数组,则表示元素序列并且对应于作为数组的伪参数的实际参数是与伪参数关联的序列。 实际参数的等级和形状不一定与伪参数的等级和形状一致,但伪参数中的元素数量不得超过实际参数的元素序列中的元素数。 /强>

你的假人是明确的形状。因此,一般情况下,您无法检测到不匹配,但在这种情况下,您的虚拟hourvaldayval实际参数更大(比例为24)的事实是允许编译器提供帮助。

更一般地说,使用明确的形状假人时必须小心。

答案 2 :(得分:2)

使用假设形状的建议真的很好(所以+1那里),因为它会检测形状不匹配。但是,如果您的阵列具有相同的形状,那么您可以再次遇到麻烦。原因是,如果参数与接口中的参数匹配,编译器无法知道您打算做什么。

因此,避免问题的更好解决方案可能是使用命名参数(除了使用带有显式接口的假定形状)。在下面的示例中,sunmoon是要处理的类似数组。当你切换它们时,子程序调用仍然有效但交换使用数组。当使用命名参数时,无论你将它们放入什么顺序,子程序都会将它连接到正确的伪参数。

program named_arguments
integer, parameter :: n = 2
integer, allocatable :: sun(:,:), moon(:,:)

allocate(sun(n,n))
allocate(moon(n,n))

call mysub(sun,moon)

write(*,*) sun
write(*,*) moon

call mysub(moon,sun)

write(*,*) sun
write(*,*) moon

call mysub(night=moon,day=sun)

write(*,*) sun
write(*,*) moon

contains

subroutine mysub(day,night)
integer :: day(:,:), night(:,:)

day = 1
night = 2
end subroutine

end program

由于您可能会为反映其用法的伪参数提供有意义的名称,因此将它们按名称连接到调用中的实际参数是避免此类问题的好习惯。

在你的情况下:

call mysub(dayval=daygrid,hourval=hourgrid,...)

会做正确的事情,因为使用命名参数并不依赖伪参数的顺序。