在《Fortran 90程序中的错误可能会让你惊讶》这篇文章中
调用Fortran 90风格例程的危险
program main real, dimension(5) :: x x = 0. ! THIS IS WRONG call incb(x) print *, x end program main subroutine incb(a) ! this is a fortran90 style subroutine real, dimension(:) :: a a = a + 1. end subroutine incb
说明子程序incb使用Fortran 90样式的假定形状数组(包含维度(:))。这样的例程必须在模块,或者在使用它们的地方具有显式接口。在这个例如,两个都不是真的。
调用这类过程的一种正确方法是使用显式的接口如下:program main real, dimension(5) :: x ! THIS IS THE RIGHT WAY interface subroutine incb(a) real, dimension(:) :: a end subroutine incb end interface x = 0. call incb(x) print *, x end program main subroutine incb(a) ! this is a fortran90 style subroutine real, dimension(:) :: a a = a + 1. end subroutine incb
如果例程在模块中,则自动生成接口并且不需要明确地写
! THIS IS ANOTHER RIGHT WAY module inc contains subroutine incb(a) ! this is a fortran90 style subroutine real, dimension(:) :: a a = a + 1. end subroutine incb end module inc program main use inc real, dimension(5) :: x x = 0. call incb(x) print *, x end program main
如果使用接口,接口必须与实际功能匹配。
所以继续我的问题,在gfortran
或其他编译器中是否有一个选项来防止编译,如果有一个调用其接口不是显式定义的过程(或在模块中定义)?
如果不是,它不应该是一个功能吗?
对于gfortran,有编译选项-Wimplicit-interface
:
-Wimplicit-procedure
如果调用的过程既没有显式接口,也没有声明为EXTERNAL,则发出警告。
这可以与-Werror
相结合,将此视为错误。
关于编译这个(使用gfortran 4.8.2)
call heffalump(1)
end
看到
但是,请注意,尽管这对于新开发的现代代码中的"愚蠢错误"可能是一个有用的测试,但事情可能非常正确,但仍然无法通过此测试。参见Vladimir F对这个答案的评论。调用大象(1)
处使用隐式接口调用过程'heffalump'
1
警告:在(1)
当然,编译器在大多数情况下无法判断过程是否需要显式接口。
是的,编译器有这个功能。如果fort有-warn interfaces
,包含在-warn
中,gfortran在-Wall
中有这个检查。
interf.f90:6.15:
call incb(x)
1
Error: Procedure 'incb' at (1) with assumed-shape dummy argument 'a' must have an explicit interface
但是,如果它们驻留在不同的文件中,编译器将在检查这一点时遇到问题。有些人会找到,有些人不会。
> gfortran incb.f90 interf.f90 -Wall
> ifort incb.f90 interf.f90 -warn
interf.f90(6): error #7978: Required interface for passing assumed shape array is missing from original source [X]
call incb(x)
----------------^
compilation aborted for interf.f90 (code 1)
正如@francesalus所写的,你可以强制对隐式接口-Wimplicit-interface
发出警告。然而,这做了一些不同的事情。它警告每个具有隐式接口的过程,即使它符合标准。
如果你将它与-Werror
连接,你将不得不为每个使用缓冲区的MPI过程编写一个接口,到你使用的每个遗留库。我使用它,但我的代码严格地在模块中,我真的必须为我使用的每个MPI过程编写接口,发送或接收一些缓冲区。对于每种类型的缓冲区,您都需要单独的接口(至少在当前的Fortran 2008中)。
更糟糕的是,一些MPI实现为某些过程提供显式接口,而另一些则没有。一旦您努力为一个MPI库版本声明了必需的接口,另一个MPI库版本就会开始抱怨接口已经定义并且它们不同。(来自战壕的真实故事)