新实现与旧实现之间的区别

时间:2013-10-19 00:20:37

标签: fortran gfortran fortran77

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

c   main program
    call foo(2)
    print*, 2
    stop
    end
    subroutine foo(x)
        x = x + 1
        return
    end   
  • 在Fortran IV的一些实现中,上面的代码将打印3.为什么?你能提出一个解释吗?
  • 您如何看待更近期的Fortran实施解决问题?

非常感谢帮助。谢谢。

1 个答案:

答案 0 :(得分:5)

程序打破了语言规则 - 子程序中的伪参数x通过行x = x + 1修改,但它与表达式(简单常量)相关联。通常,不能修改由表达式产生的值。

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

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

从Fortran 90开始,设备被引入到该语言中,以允许程序员编写新的代码,这对于编译器来说是可行的,以检查这些错误(在某些情况下,编译器需要检查如果它们被视为符合标准,则为错误)。

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

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

此外,Fortran 90引入了 intent属性 - 一个过程的伪参数的特征,这也是过程接口的特征。参数的意图向编译器指示过程是否可以定义参数(它还可能对默认初始化和组件分配状态有影响),因此表达式是否可以是有效的实际参数。子例程x中的foo通常会被声明为INTENT(INOUT)。

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

相关问题