2017-02-26 117 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的目的(如果真的有必要)。