问题
I've noticed that variables in a (child) module, which are used by a parent modules are accessible in a main program through just the parent module. This is one concept which clearly distinguishes use
statement in Fortran from include
statement in C/C++. The following programs clearly illustrate this concept.
a.f90
module a_mod
use b_mod
implicit none
integer :: a
end module
b.f90
module b_mod
use c_mod
implicit none
integer :: b
end module
c.f90
module c_mod
implicit none
integer :: c = 10
contains
subroutine inc_c
c = c + 10
end subroutine inc_c
end module
test.f90
program test
use a_mod
implicit none
call inc_c
write(*,*),c
end program
Note that I am able to call a function in c_mod
by just using a_mod
. Note that I cannot directly observe that c_mod
is available unless I traverse the dependency list.
But in a complicated software, is there a simple way to know (say, using an IDE) if a variable is available for use at a particular line?
回答1:
The best thing to do, in my opinion, is to avoid the use of blanket use
statements, especially for large and sometimes unwieldy modules. Instead, specify which module entities to inherit via the only
keyword, such as:
program main
use a_mod, only : c, inc_c
implicit none
call inc_c
write(*,*) c
end program main
This works, but it's confusing because a_mod
isn't the real owner of c
and inc_c
. Therefore, you should try to use
entities from where they are actually declared, which gives:
program main
use c_mod, only : c, inc_c
! ^ This has changed
implicit none
call inc_c
write(*,*) c
end program main
Now, anybody reading the code has a clear notion of which variables and subroutines are in scope and where they come from.
Finally, this has the added benefit of reducing the risk that you use c
without realizing it's actually inhereted from c_mod
. This is particularly a problem when not using implicit none
!
回答2:
As Vladimir F suggested in a comment, you can solve this issue using private
and public
statements in your modules. If you rewrite your modules like this:
module a_mod
use :: b_mod
private
public :: a
integer :: a
end module
module b_mod
use :: c_mod
private
public :: b
integer :: b
end module
module c_mod
private
public :: c, inc_c
integer :: c = 10
contains
subroutine inc_c
c = c + 10
end subroutine
end module
In this case, the statement private
in the beginning of each module means that quantities declared in the module are not exported by default. You now have to explicitly declare what variables and subroutines to make available when you use
the module by adding a public
statement. (This could alternatively be done in one line using the syntax integer, public :: c = 10
.) This practice prevents c_mod
variables from leaking out of b_mod
, and so on.
回答3:
Though not inituitve like IDE, gfortran can print a list of imported symbols by attaching the -fdump-fortran-original
(or -fdump-parse-tree
) option. To do so, we first generate *.mod file as
gfortran -c {c,b,a}.f90
and compile the desired source as
gfortran -fdump-fortran-original -c test.f90
Then, we get a list of imported symbols like this:
Namespace: A-Z: (UNKNOWN 0)
procedure name = test
symtree: 'a' || symbol: 'a'
type spec : (INTEGER 4)
attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(a_mod))
symtree: 'a_mod' || symbol: 'a_mod'
type spec : (UNKNOWN 0)
attributes: (MODULE USE-ASSOC(a_mod))
symtree: 'b' || symbol: 'b'
type spec : (INTEGER 4)
attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(b_mod))
symtree: 'b_mod' || symbol: 'b_mod'
type spec : (UNKNOWN 0)
attributes: (MODULE USE-ASSOC(b_mod))
symtree: 'c' || symbol: 'c'
type spec : (INTEGER 4)
attributes: (VARIABLE IMPLICIT-SAVE USE-ASSOC(c_mod))
symtree: 'c_mod' || symbol: 'c_mod'
type spec : (UNKNOWN 0)
attributes: (MODULE USE-ASSOC(c_mod))
symtree: 'inc_c' || symbol: 'inc_c' <---
type spec : (UNKNOWN 0) <---
attributes: (PROCEDURE MODULE-PROC USE-ASSOC(c_mod) SUBROUTINE) <---
symtree: 'test' || symbol: 'test'
type spec : (UNKNOWN 0)
attributes: (PROGRAM PUBLIC SUBROUTINE)
(For example, the lines with arrow indicates that a routine inc_c
is available from c_mod
.) If we modify test.f90 so as to attach the only
keyword,
program test
use a_mod, only: inc_c
implicit none
call inc_c
end program
then the output is also simplified accordingly:
Namespace: A-Z: (UNKNOWN 0)
procedure name = test
symtree: 'a_mod' || symbol: 'a_mod'
type spec : (UNKNOWN 0)
attributes: (MODULE USE-ASSOC(a_mod))
symtree: 'inc_c' || symbol: 'inc_c'
type spec : (UNKNOWN 0)
attributes: (PROCEDURE MODULE-PROC USE-ASSOC(c_mod) SUBROUTINE)
symtree: 'test' || symbol: 'test'
type spec : (UNKNOWN 0)
attributes: (PROGRAM PUBLIC SUBROUTINE)
So, althogh I've never used this option for this purpose, it might be of some use for the OP's purpose (if really necessary).
来源:https://stackoverflow.com/questions/42474530/scope-of-variables-in-case-of-modules-used-by-modules-in-fortran