Function Fortran是否通过函数和子例程调用保留内部变量的值?

Function Fortran是否通过函数和子例程调用保留内部变量的值?,function,fortran,scope,subroutine,Function,Fortran,Scope,Subroutine,经过痛苦的调试之后,我相信我已经找到了Fortran的一个独特属性,我想在stackoverflow这里验证一下 我注意到的是,至少内部逻辑变量的值在函数或子例程调用中被保留 下面是一些示例代码来说明我的观点: PROGRAM function_variable_preserve IMPLICIT NONE CHARACTER(len=8) :: func_negative_or_not ! Declares function name INTEGER :: input CHARACTER(l

经过痛苦的调试之后,我相信我已经找到了Fortran的一个独特属性,我想在stackoverflow这里验证一下

我注意到的是,至少内部逻辑变量的值在函数或子例程调用中被保留

下面是一些示例代码来说明我的观点:

PROGRAM function_variable_preserve
IMPLICIT NONE

CHARACTER(len=8) :: func_negative_or_not ! Declares function name
INTEGER :: input
CHARACTER(len=8) :: output

input = -9

output = func_negative_or_not(input)
WRITE(*,10) input, " is ", output
10 FORMAT("FUNCTION: ", I2, 2A)

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output
20 FORMAT("SUBROUTINE: ", I2, 2A)

WRITE(*,*) 'Expected negative.'


input = 7
output = func_negative_or_not(output)
WRITE(*,10) input, " is ", output

CALL sub_negative_or_not(input, output)
WRITE(*,20) input, " is ", output

WRITE(*,*) 'Expected positive.'

END PROGRAM function_variable_preserve

CHARACTER(len=*) FUNCTION func_negative_or_not(input)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    func_negative_or_not = 'negative'
ELSE 
    func_negative_or_not = 'positive'
END IF

END FUNCTION func_negative_or_not

SUBROUTINE sub_negative_or_not(input, output)
IMPLICIT NONE

INTEGER, INTENT(IN) :: input
CHARACTER(len=*), INTENT(OUT) :: output
LOGICAL :: negative = .FALSE.

IF (input < 0) THEN
    negative = .TRUE.
END IF

IF (negative) THEN
    output = 'negative'
ELSE 
    output = 'positive'
END IF

END SUBROUTINE sub_negative_or_not
如您所见,函数或子例程调用一次后,逻辑变量
negative
(如果切换到
.TRUE.
)将保持不变,尽管在类型声明语句中将
negative
初始化为
.FALSE.

当然,我可以通过添加一行来纠正这个问题 否定=.FALSE。 在我的函数和子例程中声明变量后

然而,我觉得很奇怪,这是必要的


<强>为了便于移植和代码重用,在每次调用子程序或函数时,语言(或编译器)是否需要重新初始化所有内部变量?>/P>> P>这与C或C++中的代码>静态< /代码>函数范围变量没有太大的不同。 编程语言设计在

FORTRAN
诞生时还处于初级阶段 发达的。如果它是从零开始设计的,毫无疑问,许多设计 决定会有所不同

最初,
FORTRAN
甚至不支持递归,没有动态内存 分配时,程序使用
COMMON
块玩各种类型的双关游戏 和
等价性
语句,过程可能有多个入口点…因此 内存模型基本上是让编译器/链接器布局所有内容,甚至是本地的 变量和数值文字常量,放入固定存储位置,而不是打开 那一堆。如果需要,您甚至可以编写代码,将“2”的值更改为 "42"!

到目前为止,已经有很多遗留的
FORTRAN
代码,编译器编写人员竭尽全力保持向后兼容的语义。我无法引用你提到的强制要求行为的标准中的章节,也无法引用其基本原理,但向后兼容性胜过现代语言设计敏感性似乎是合理的,在本例中。

回答您的问题:是的,Fortran确实通过函数和子例程调用保留内部变量的值

在某些情况下

如果使用SAVE属性声明内部变量,则它的值将从一个调用保存到下一个调用。当然,这在某些情况下是有用的

然而,当您第一次了解Fortran的一个问题时,您的问题是一个常见的反应:如果您在声明中初始化内部变量,那么它会自动获取SAVE属性。您在子例程中完全做到了这一点。这是符合标准的。如果你不想发生这种情况,不要在声明中初始化


这是(一些)新来者对这门语言感到惊讶和抱怨的原因。但不管他们怎么抱怨,它都不会改变,所以你只需(a)了解它,并(b)意识到它就可以了。

这已经在这里讨论过好几次了,最近一次是在

你不必通过实验来发现这种行为,更好的教科书中已经明确说明了这一点

不同的语言是不同的,有不同的行为


这种行为有其历史原因。Fortran 77和更早版本的许多编译器在过程调用中保留了所有局部变量的值。程序员不应该依赖这种行为,但许多人确实如此。根据标准,如果希望局部变量(非公共)保留其值,则需要使用“保存”。但许多程序员忽略了这一点。在那个时代,程序很少被移植到不同的平台和编译器,所以错误的假设可能永远不会被注意到。在遗留程序中经常会发现这个问题——当前的Fortran编译器通常会提供一个编译器开关来保存所有变量。语言标准要求所有局部变量保留其值是愚蠢的。但是,挽救许多不小心使用“SAVE”的程序的中间要求是,要求声明中初始化的所有变量自动具有SAVE属性。因此,您发现……

fortran中无疑存在一些遗留问题,如果今天由stratch编写,将以不同的方式处理,但请不要让它听起来像是一种遗留语言。恰恰相反——从许多方面来说,它具有其他“现代”语言所不具备的功能(例如,在c.l.f.上,讨论通常与f03/最新的c标准有关,这就是C99?@Idigas:好的观点!我并不是想暗示FORTRAN是一块化石……只是遗产方面似乎最符合CmdrGuard的问题,所以这就是我所关注的;很抱歉。我的错误。你剩下的答案说得很好。我相信(为了确保我必须去检查标准,我现在没有)从2003年开始,所有变量都有SAVE属性。@rook:在什么情况下,哪些变量自动有
SAVE
?@jvriesem-我不理解这个问题。“在什么情况下”?你能详细说明一下吗?@Rook:当然。我知道,如果一个子例程被声明为
elemental
,它就会被自动声明为
pure
。类似地,我知道模块变量(至少是某些变量)自动具有
save
属性,但我不知道是否存在
save
属性为隐式和/或自动的其他上下文
FUNCTION: -9 is negative
SUBROUTINE: -9 is negative
 Expected negative.
FUNCTION:  7 is negative
SUBROUTINE:  7 is negative
 Expected positive.