为什么我必须在Fortran中为函数的双精度返回值隐式指定? [英] Why do I have to specify implicitly for a double precision return value of a function in Fortran?
问题描述
我是Fortran新手,我正在尝试common
块。我的代码很简单
program main
implicit double precision (p)
real * 8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end program main
function power(x)
implicit none
real * 8 :: power
real * 8 :: x, y
common /yvalue/ y
power = x ** y
end function power
它可以工作,但如果我注释掉第二行,它隐式声明以p
开头的变量为双精度,编译器会报告以下
Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
我知道返回值power
默认情况下是一个单精度变量,但为什么在函数中声明power
为双精度是不够的?为什么在main
中写入real * 8 power
也不起作用?
推荐答案
当您尝试在代码中调用的过程(函数或子例程)位于program
主体之外并且不是任何module
的一部分时,它被命名为外部函数(或子例程)。
Fortran是一种静态类型的语言,因此在编译时必须知道所有变量和函数的类型。因此,如果要在程序中引用外部函数,必须有一种方法让程序知道它的返回类型。您有3个(不好的)选项,我将从最差的开始列出它们:
- 最差:依赖隐式类型规则,该规则恰好将外部函数的返回类型与调用方中与其标识符相关联的类型相匹配(如您在示例中所做的那样)。
为什么不应该这样做?因为这是癌症。它使代码的含义变得模糊,你不知道这个名字指的是什么。在某些情况下,它甚至可能看起来像一个数组变量,而不是一个函数。此外,在这种情况下,编译器不会检查参数一致性,因此如果您没有打开特定的编译器选项,代码将在运行时失败,或者更糟糕的是,将给出错误的结果。此外,隐式类型现在很少有用,大多数情况下这是自找麻烦。始终使用implicit none
!
p
开头的变量都将是默认的real
类型(在您的编译器中,它是real(4)
)。由于您将函数结果声明为real*8
,而您的编译器将其解释为real(8)
(请参见最后的注释),因此出现错误。
- 不好:在调用方的规范区域中声明函数的名称和类型。
这样做就像声明变量一样:
program main
implicit none
real*8 :: x, y, power
顺便说一句,属性external
可以应用于像您这样的外部过程。它不仅可以为过程提供一些属性(可以作为实际参数传递,消除内在过程的歧义),还可以使标识符的来源更加清晰。
program main
implicit none
real*8 :: x, y, power
external :: power
为什么不应该这样做?编译器也不检查参数。这严重限制了您与外部函数通信的选择:参数不能是假定形状、假定排名、多态、参数化、共数组,也不能在被调用方声明为allocatable
、optional
、pointer
、target
、asynchronous
、volatile
或value
;返回类型不能是数组、指针或可分配类型;该函数不能作为参数传递,BEelemental
,如果pure
,则不能在此类上下文中使用。造成这一切的原因是缺乏显式接口。
- 可接受:为调用方中的外部函数指定
interface
。
这样:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
这样,编译器就能够知道声明的所有细节,而我提到的所有限制都不适用。完全自由和代码清晰!
为什么不应该这样做?因为有一个更好的方法,那就是使用modules
!在不能使用模块的情况下,例如在使用已经存在的大型旧代码时,这样做是完全可以的。缺点是,您在两个不同的位置拥有几乎相同的代码,并且它们必须始终匹配。
奖励:更好:使用模块。
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
甚至可以选择在
contains
之后将您的函数直接包含到program
中。仅当您不打算在其他程序单元中重用此函数时,才建议这样做。@IanBush的answer报道了这一情况。
最后注意:查看this answer,了解real*8
语法不规范的原因,应避免使用。
这篇关于为什么我必须在Fortran中为函数的双精度返回值隐式指定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!