2017-02-26 195 views
3

我注意到,父模块使用的(子)模块中的变量只能通过父模块在主程序中访问。这是一个概念,它明确区分了Fortran中的use语句与C/C++中的include语句。以下程序清楚地说明了这个概念。Fortran中模块使用的模块的变量范围

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 

注意,我能够通过只使用a_mod调用函数中c_mod。请注意,我不能直接观察到c_mod可用,除非我遍历依赖项列表。

但是在一个复杂的软件中,是否有一种简单的方法可以知道(比如说,使用IDE)如果某个变量可用于特定行?

+0

每个IDE都不同。这不能真正回答。一些IDE可能提供此功能,其他IDE可能不提供此功能许多Fortran程序员根本不使用任何IDE。 –

+3

请注意,Fortran使用'private','public'和'only'具有更好的Fortran可访问性。 –

回答

2

在我看来,最好的做法是避免使用毯子use声明,特别是对于大型且有时难以使用的模块。相反,指定通过only关键字继承该模块的实体,如:

program main 
    use a_mod, only : c, inc_c 
    implicit none 

    call inc_c 
    write(*,*) c 
end program main 

这工作,但它的混淆,因为a_mod不是cinc_c真正的主人。因此,你应该尝试从他们实际上宣布use实体,这给:

program main 
    use c_mod, only : c, inc_c 
    ! ^This has changed 
    implicit none 

    call inc_c 
    write(*,*) c 
end program main 

现在,任何人阅读代码有一个清晰的概念,其中的变量和子程序在范围和他们来自哪里。

最后,这还有一个额外的好处,即降低使用c而不知道它实际上是从c_mod中插入的风险。当不使用implicit none时,这是一个特别的问题!

1

正如Vladimir F在评论中建议的那样,您可以在模块中使用privatepublic语句来解决此问题。如果重写模块是这样的:

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 

在这种情况下,在每个模块的开始声明private意味着该模块中声明的数量是默认被导出。您现在必须通过添加public语句明确声明在模块use模块中可用的变量和子程序。 (也可以使用语法integer, public :: c = 10在一行中完成。)这种做法可以防止c_mod变量泄漏出b_mod等等。

+0

我不认为这有效解决了这个问题。重点是在'b_mod'的'c_mod'中使用'c'和'inc_c'。使这些实体保密。 – Ross

+0

我并不是建议你让条目在任何地方都是私有的。我建议你在'c_mod'中将它们设置为'public'(以便它们*在你使用:: c_mod'时被导入),但是在'b_mod'中使用相同的变量'private'(这样它们是*当您使用:: b_mod或use :: a_mod时,不会导入*)。我相信,这确实解决了这个问题。 – jabirali

+0

请注意,在我的'c_mod'版本中,我显式声明'public :: c,inc_c',而您的评论表明您认为我将它们设置为'private'。 – jabirali

0

尽管不像IDE一样,gfortran可以通过附加-fdump-fortran-original(或-fdump-parse-tree)选项来打印导入的符号列表。要做到这一点,我们首先生成* mod文件作为

gfortran -c {c,b,a}.f90 

和编译所需的源作为

gfortran -fdump-fortran-original -c test.f90 

然后,我们得到这样的进口符号列表:

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) 

(例如,带箭头的行表示例程inc_c可从c_mod获得。)如果我们修改test.f90以附加only关键字

program test 
    use a_mod, only: inc_c 
    implicit none 

    call inc_c 
end program 

则输出也相应简化:

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) 

所以,althogh我从未使用过该选项用于此目的,它可能是一些使用了OP的目的(如果真的有必要)。