我一直在用科学(学术)软件进行机械分析。现在,代码从八十年代(Fortran 77)开始,以混合/混合形式的Fortran 90/95到达我。但是,由于添加像MKL这样的强大工具的必要性,我决定从旧的英特尔Visual Fortran 11.072(使用VS2008)转移到“最近的”14.0(在ComposerXE 2013中)。 F77核心编译没有问题,但我遇到了子程序中的一些接口的问题,这些接口处理变量的延迟定义。我做了一个能够重复这些问题的MWE,而不是用大量的惯例来讨厌。
迷你程序将在下面复制,因此您可以修改它:
program main
implicit none
print *, 'Start of the program'
call mainsub
print *, 'End of the program'
pause
end program
有一个模块problem.f定义大小:
module problem
implicit none
save
integer, parameter :: size1 = 6
integer, parameter :: size2 = 3
integer, parameter :: size3 = 18
end module problem
因此,有一个主子程序调用“第一级”子程序:
SUBROUTINE mainsub
use problem ! here there are the dimensions defined
implicit none
! Scalars (almost)
REAL*8 :: sca01, sca02(size2), sca03
! Vectors
REAL*8 :: arr01(size1)
REAL*8 :: arr02(size1)
REAL*8 :: arr03(size3)
REAL*8 :: arr04(size1)
! Matrices
REAL*8 :: mat01(size1,size1)
REAL*8 :: mat02(size3)
! trying to trick IFORT with interface (hiding dimension)
print *, 'Calling sub11'
CALL sub11(arr01)
print *, 'Calling sub11 - end'
pause
print *, 'Calling sub12'
CALL sub12(arr02,arr03,arr04)
print *, 'Calling sub12 - end'
pause
print *, 'Calling sub13'
CALL sub13(mat01,mat02)
print *, 'Calling sub13 - end'
pause
print *, 'Calling sub14'
CALL sub14(sca01,sca02,sca03)
print *, 'Calling sub14 - end'
pause
contains
subroutine sub11(arr01)
use problem
implicit none
REAL*8, DIMENSION(:) :: arr01
print *, 'This is sub11, size arr01: ', SIZE(arr01), SHAPE(arr01)
CALL sub21(arr01)
end subroutine
end subroutine
这些是“第一级”子程序
SUBROUTINE sub12(arr02, arr03, arr04)
use problem
implicit none
REAL*8 :: arr02(*)
REAL*8 :: arr03(size3)
REAL*8 :: arr04(*)
REAL*8 :: dummy(600)
print *, 'sub 12'
call sub22(arr02, dummy, arr04)
END SUBROUTINE
SUBROUTINE sub13(mat01,mat02)
use problem
implicit none
REAL*8 :: mat01(size1,size1)
REAL*8 :: mat02(size3,*)
print *, 'sub 13'
call sub23(mat01, mat02)
END SUBROUTINE
SUBROUTINE sub14(sca01,sca02,sca03)
use problem
implicit none
REAL*8 :: sca01, sca02(*), sca03
REAL*8 :: dummy(600)
print *, 'sub 14'
call sub24(sca01, dummy, sca03)
END SUBROUTINE
最后这些是“第二级”子程序:
SUBROUTINE sub21(arr01)
use problem
implicit none
REAL*8 :: arr01(size3,size1)
print *, 'This is sub21, size arr01: ', SIZE(arr01)
END SUBROUTINE
SUBROUTINE sub22(arr02, arr03, arr04)
use problem
implicit none
REAL*8 :: arr02(size3)
REAL*8 :: arr03(size3)
REAL*8 :: arr04(size2,size3)
print *, 'sub22'
print *, SIZE(arr02)
print *, SIZE(arr03)
print *, SIZE(arr04)
END SUBROUTINE
SUBROUTINE sub23(mat01,mat02)
use problem
implicit none
REAL*8 :: mat01(size1,size2)
REAL*8 :: mat02(size1,size2,size3)
print *, 'sub 23'
print *, SHAPE(mat01), SIZE(mat01)
print *, SHAPE(mat02), SIZE(mat02)
end subroutine
SUBROUTINE sub24(sca01,sca02,sca03)
use problem
implicit none
REAL*8 :: sca01, sca02(*), sca03
print *, 'sub 24'
print *, SHAPE(sca01), SHAPE(sca03)
end subroutine
此代码在我的机器上使用英特尔Fortran 14正确编译。现在,让我们考虑可能出现的一系列案例。
常见变量不匹配 如果我将一个实际变量定义为Real * 8并且在子程序中相应的虚拟变量是Real * 4,或者混合Real * 8 - >整数* 8,编译器识别不匹配并给出错误。类似地,如果我定义标量变量Real sca01并且在子例程中我将其定义为Real sca01(*)或Real sca01(size1),则编译器再次识别出一个是数组而另一个不是数组,因此它会抛出错误。 (错误#6633:实际参数的类型与伪参数的类型不同。)
数组大小不匹配 如果将一个数组定义为arr02(size1)并且在被调用的子例程arr02(size2)中,则只有在运行时检查错误处于活动状态并且整数size1,size2被声明为参数时(如在模块问题.f)。
但是,我在两个定义的中间放了一个中间子程序,比如上面的MWE:
sub11 -- sub21
/
mainsub --- sub12 -- sub22
\
sub13 -- sub23
具有CONTAINS语句的接口( mainsub 到 sub11 )会检查实际变量和虚拟变量的大小和尺寸是否一致。但是,它不会检查下一次对 sub21 的调用是否会在接口子程序的出路上失去跟踪大小。
在 sub12 中,通过使用假定的形状数组(*)定义,我可以根据需要更改形状和大小。当然,我会在某些时候出现分段错误,但即使我有所有运行时检查和常量大小,也不会抛出任何错误或警告。
最后,对于 sub12 ,这个技巧也可以在多个维度上运行,有时即使它不是形状假定的数组,就像在mat02的情况下一样(这很奇怪......)。 / p>
因此,我几乎没有问题:
接口定义与(*)和(:)之间的区别是什么?
如果(*)类似于数组大小的延迟定义,为什么它不适用于标量? (假设标量为1x1阵列) 为什么不通过子程序检查尺寸?
未对阵列进行多次大小检查。现在,使用英特尔Fortran 14,我有很多#6633,#6634和#8284错误。它改变了什么?
鉴于这个混合的Fortran77 / 90/95全景图,我应该考虑哪些定义要维护,哪些不是? (显然是上面使用的,而不是面向对象的,因为它是一个程序程序)
那么Fortran中变量定义的哲学(主要的实际原因)是什么?如果我可以用程序程序“欺骗”编译器(并且大小是常量,没有可分配的),我想我错过了一些东西。
我想对这个问题的长度道歉,但是仅仅研究过Fortran而没有CS背景,我觉得我错过了这个问题的主旨......
谢谢!
答案 0 :(得分:3)
对于伪参数,dummy(*)
声明一个假设的大小数组,dummy(:)
声明一个假定的形状数组[并且为了完整性,dummy(some_expression)
声明一个显式的形状数组]。
对于假设的大小数组:
实际参数必须是可以产生数组元素序列的东西,但实际参数的尺寸不需要与虚拟的尺寸相同。
在使用dummy的过程中,实际参数的大小不会自动知道,并且您无法对需要该大小的伪参数调用操作(例如,不允许SIZE(dummy)
。如果由于某种原因,在过程中需要由实际参数指定的数组元素序列的大小,然后用户需要单独传递它。
在调用过程的作用域中不需要显式接口。 (假设大小是Fortran 77中的概念,在语言具有显式接口的概念之前。)
对于假定的形状数组:
实际参数必须与排名匹配。
在程序中,实际参数的大小和形状可以通过假人自动获得。
在调用该过程的任何范围内都需要显示该过程的显式接口。
显式大小数组与假定大小数组类似,但在过程中,数组的大小是已知的(因为它是显式声明的!)。实际参数指定的数组元素序列的大小必须与明确指定的大小相同或更大。
作为标量变量名称的实际参数(不是CHARACTER类型,默认类型或C_CHAR类型)不指定数组元素序列。作为一般原则,标量不是数组。
已经对编译器在程序中查找错误的能力进行了改进。此外,与错误检查相关的某些编译器选项可能已更改默认值。 (请注意,不同的编译器在此区域具有不同的诊断功能。)
哪种类型的数组声明(以及除此处讨论的其他声明之外的其他类型)最好取决于您要执行的操作,但作为新代码的准则,如果假定形状的限制不会导致问题,然后使用假定的数组形状。
无法保证编译器会捕获所有编程错误。不同的声明用于不同的目的。