2

我是 Fortran 的新手。请看下面的代码:

c   main program
    call foo(2)
    print*, 2
    stop
    end
    subroutine foo(x)
        x = x + 1
        return
    end   
  • 在 Fortran IV 的某些实现中,上面的代码会打印一个 3。这是为什么呢?你能建议一个解释吗?
  • 你认为最近的 Fortran 实现如何解决这个问题?

非常感谢您的帮助。谢谢你。

4

1 回答 1

5

该程序违反了语言规则 -x子例程中的虚拟参数通过 line 修改x = x + 1,但它与表达式(一个简单的常量)相关联。通常,不能修改由表达式产生的值。

该特定代码在 Fortran 2008 的语法上仍然有效。它在 Fortran 2008 中仍然是一个编程错误——就像在 Fortran IV/66 中一样。这不是编译器需要诊断的东西。有些可能,也许有额外的调试选项,也许直到运行时。

因为该程序违反了语言规则,所以当您运行该程序时,任何事情都可能发生。究竟什么取决于编译器生成的代码。编译器可能已经为表达式产生的值留出了可修改的存储空间,这样它在内部看起来像一个变量(程序可能会打印三个并且程序继续执行),可修改的存储空间可能会在程序中共享给其他实例常量2(突然的值2到处变成三个!),常量值的存储可能在不可修改的内存中(程序可能会崩溃),编译器可能会发出错误消息,程序可能会感到不安和闷闷不乐卧室,该程序可能会向邻国宣战 - 这是一个编程错误 - 会发生什么未指定。

从 Fortran 90 开始,语言中引入了一些工具,允许程序员编写代码,这些代码对于编译器检查此类错误是实用的(在某些情况下,如果将错误视为标准,编译器需要检查错误符合)。

对于呈现的代码,主程序和子程序被视为分开编译 - 主程序不知道子程序的细节,反之亦然(子程序可能在主程序之后很长时间编译,在不同的机器上,两者的输出在稍后的某个阶段被链接在一起——没有花哨的链接时间行为或静态分析,因此不可能解决诸如此类的错误)。语言规则是这样的,当编译主程序时,编译器必须仅根据引用子程序的方式隐式假设子程序接口的细节——在主程序内部,子程序有一个隐式接口

Fortran 90 引入了显式接口的概念,其中编译器以各种方式明确地告知子程序的接口是什么,然后可以检查对子程序的任何引用是否与该接口一致。如果一个过程是模块过程、内部过程或内在过程——该接口是自动实现的,或者对于外部子程序、过程指针等,程序员可以使用接口块显式地描述接口。

此外,Fortran 90 引入了intent 属性——过程的虚拟参数的特性,它也是过程接口的特性。参数的意图向编译器指示过程是否可以定义参数(它也可能暗示默认初始化和组件分配状态),因此表达式是否可以是有效的实际参数。 xin 子程序foo通常会声明为 INTENT(INOUT)。

当使用具有基本实现质量的编译器时,这些新的语言特性共同提供了针对此类编程错误的强大防御。如果您从该语言开始,那么建议将这些新功能作为您的标准方法的一部分 - 即使用隐式无,所有过程通常应该是模块过程或内部过程,仅在绝对需要时使用外部过程,始终指定虚拟参数意图,使用自由形式的源代码。

于 2013-10-19T01:34:06.757 回答