Contains statement

2020-06-17 03:26发布

问题:

I am not understanding the importance of CONTAINS statement in fortran 90

For example

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

and one by defining subroutines outside the main program. I understand for functions, one need to specify the type of the function, but for subroutines it is not required. I am interested in understanding whether there are any additional caveats in doing so?

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

回答1:

In both your first and second versions try changing the line

CALL ABC(i,j,k)

to

CALL ABC(i,j)

and see what happens, firstly at compile time and secondly at run time.

When you have done that, and reported back on your findings, I can turn this into a proper answer.

OK, so here's the answer, most of which you've already figured out:

In the old days, before Fortran 90, it was common for FORTRAN (everyone shouted the name in those days) programs to be compiled in separate 'units' (it still is). In your second version the program and the subroutine are in separate units and are compiled separately. There is no information available to the compiler to check that the call to the subroutine matches the subroutine signature -- that is left to the programmer to check. Call the subroutine incorrectly and almost anything can happen -- if you're lucky the program crashes or produces obviously erroneous results, if you're unlucky it produces not-obviously-erroneous-but-still-erroneous results.

If you include the source code for the subroutine in the scope of the program unit, and use the contains section, as in your first version of your program, the compiler will create an interface for the subroutine and can check that any calls made to the subroutine are formally correct. Hence the failure to compile you discovered.

The other way to have the compiler generate the interface for subroutines, and these approaches work for functions too, is to put them into a module and use the module in the program. You'll find many examples of how to do this in other Qs and As here on SO.

Putting the subroutine into a module isn't exactly the same as including it in a contains section. In the contains section the subroutine can use variables declared in the program without their being passed through the subroutine's argument list. This is rather frowned upon as poor programming practice but you do come across it in the wild.