Scope of variables in case of modules used by modules in Fortran

前端 未结 3 857
名媛妹妹
名媛妹妹 2021-01-21 01:17

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 c

相关标签:
3条回答
  • 2021-01-21 01:35

    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).

    0 讨论(0)
  • 2021-01-21 01:43

    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.

    0 讨论(0)
  • 2021-01-21 01:48

    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!

    0 讨论(0)
提交回复
热议问题