当您尝试在代码中调用的过程(函数或子例程)位于outside你的身体program
并且也不属于任何module
,它被命名为外部函数(或子程序)。
Fortran 是一种静态类型语言,因此必须在编译时知道所有变量和函数的类型。因此,如果您想在程序中引用外部函数,则必须有一种方法让程序知道其返回类型。你有 3 (bad)选项,我将从最差的开始列出它们:
-
WORST:依赖隐式类型规则,该规则恰好将外部函数的返回类型与调用者中与其标识符关联的类型相匹配(正如您在示例中所做的那样)。
为什么你不应该这样做? 因为它是癌症。这使得代码的含义变得模糊,你无法知道这个名字指的是什么。在某些情况下,它甚至可能看起来像一个数组变量,而不是一个函数。此外,在这种情况下,编译器不会检查参数一致性,因此如果您没有打开特定的编译器选项,代码将在以下位置失败:runtime,或更糟糕的是,会给出错误的结果。此外,隐式类型现在很少有用,大多数时候这是自找麻烦。总是使用implicit none
!
正如您所指出的,根据隐式类型的默认规则,任何名称以p
将被默认real
类型(在你的编译器中,它是real(4)
)。正如您将函数结果声明为real*8
,你的编译器解释为real(8)
(见最后的注释),错误就出现了。
-
BAD:在调用者指定区域声明函数的名称和类型。
就像声明变量一样,如下所示:
program main
implicit none
real*8 :: x, y, power
顺便说一句,属性external
可以应用于像您这样的外部程序。不仅仅是为过程提供一些属性(可以作为实际参数传递,消除内部过程的歧义),它还可以使标识符的起源更加清晰。
program main
implicit none
real*8 :: x, y, power
external :: power
为什么你不应该这样做?编译器也没有进行参数检查。这严重限制了与外部函数通信的选项:参数不能被假定形状、假定等级、多态、参数化、coarray 或在被调用方声明为allocatable
, optional
, pointer
, target
, asynchronous
, volatile
or value
;返回类型不能是数组、指针或可分配类型;该函数不能作为参数传递,是elemental
而如果pure
,不能在这种情况下使用。而这一切的原因就是缺乏一个显式接口.
-
可接受:指定一个
interface
对于调用者中的外部函数。
像这样:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
这样,编译器就能够知道声明的所有细节,并且我提到的所有限制都将不适用。完全自由和代码清晰!
为什么你不应该这样做?因为有更好的方法,那就是使用modules
!好吧,如果你不能使用模块,那么在上下文中执行此操作是完全可以的,例如当使用已经存在的大型旧代码时。缺点是,您在两个不同的地方有几乎相同的代码,并且它们必须始终匹配。
Bonus: BETTER:使用模块。
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
为什么你绝对应该这样做?因为使用模块,接口会自动且隐式地可用(代码重复更少,没有限制);模块可以单独重新编译和更新,而不会破坏代码。此外,您可以在模块范围内声明共享变量并避免使用common
声明。您的代码的更好版本是:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
甚至可以选择将您的功能直接包含到您的program
, after contains
。仅当您不打算在其他程序单元中重用此函数时才建议这样做。 @伊恩布什的answer https://stackoverflow.com/a/53425499/2938526涵盖了这个案例。
最后注意:看一下这个答案 https://stackoverflow.com/questions/3170239/fortran-integer4-vs-integer4-vs-integerkind-4看看为什么语法real*8
是非标准的,应该避免。