2016-03-04 154 views
2

我不理解的的重要性,通过定义主程序外的子程序中包含Fortran 90的包含声明

声明例如

PROGRAM BLABLA 

IMPLICIT NONE 

INTEGER :: i,j,k 

i = 1; j = 1;k =1 

PRINT *, i,j,k 

CALL ABC(i,j,k) 

PRINT *, i,j,k 

CONTAINS 

    SUBROUTINE ABC(r,s,t) 

    IMPLICIT NONE 

    INTEGER, INTENT(IN) :: r,s 
    INTEGER, INTENT(OUT) :: t 

    t = r + s 

    END SUBROUTINE ABC 
END PROGRAM BLABLA 

和一个。我理解函数,需要指定函数的类型,但对于子例程,它不是必需的。我有兴趣了解这样做是否有任何额外的注意事项?

PROGRAM BLABLA 

IMPLICIT NONE 

INTEGER :: i,j,k 

i = 1; j = 1;k =1 

PRINT *, i,j,k 

CALL ABC(i,j,k) 

PRINT *, i,j,k 

END PROGRAM BLABLA 

SUBROUTINE ABC(r,s,t) 

IMPLICIT NONE 

INTEGER, INTENT(IN) :: r,s 
INTEGER, INTENT(OUT) :: t 

t = r + s 

END SUBROUTINE ABC 

回答

3

在这两个您的第一和第二版本尝试改变线

CALL ABC(i,j,k) 

CALL ABC(i,j) 

看看会发生什么,首先在编译的时候,其次在运行时。

当你这样做了,并报告了你的发现后,我可以把它变成一个正确的答案。

OK,所以这里的答案,其中大部分你已经想通了:

在过去,Fortran 90的前,是常见的FORTRAN(每个人都喊在那些日子里的名字)程序编入单独的“单位”(现在仍然是)。在你的第二个版本中,程序和子程序是分开的单元并单独编译。编译器没有可用的信息来检查对子例程的调用是否与子例程签名匹配 - 这是留给程序员检查的。不正确地调用子程序,几乎任何事情都可能发生 - 如果你幸运的话,程序崩溃或产生明显错误的结果,如果你不幸,它会产生不明显错误但仍然错误的结果。

如果在程序单元的作用域中包含子程序的源代码,并使用contains部分(如在程序的第一个版本中那样),编译器将为该子程序创建一个接口,并可以检查任何对子程序的调用在形式上是正确的。因此没有编译你发现。

另一种让编译器为子程序生成接口的方法,这些方法也可以用于函数,也就是将它们放入模块中,并将其放入程序中的模块中。你会发现很多例子来说明如何在其他Q和As上实现。

将子程序放入模块中并不完全等同于将其包含在contains部分中。在contains节中,子程序可以使用程序中声明的变量,而不通过子程序的参数列表。这是一个糟糕的编程习惯,但你确实遇到过它。

+0

当我没有** CONTAINS **时,它编译,但然后给我一个错误的答案(任意大)。当我有** CONTAINS **时,它不允许我编译。所以我猜** CONTAINS **作为参数的附加检查。到目前为止,我正在编写没有** CONTAINS **的代码。如果相同的代码用** CONTAINS **编译**,我可以确信,其他代码在参数上是正确的。更确切地说,如果在任何代码中都没有传递参数(但在MODULES中保存为全局变量),两者是否都相同? – Vaidyanathan