Fortran中模块使用的模块的变量范围

时间:2017-02-26 21:35:20

标签: module include fortran fortran90

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

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

请注意,我只需使用c_mod就可以在a_mod中调用一个函数。请注意,除非我遍历依赖项列表,否则我无法直接观察到c_mod可用。

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

3 个答案:

答案 0 :(得分:2)

在我看来,最好的办法是避免使用一揽子<build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>3.0.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.mycompany.clinikeymaven.App</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> 语句,特别是对于大型且有时笨重的模块。而是通过use关键字指定要继承的模块实体,例如:

only

这很有效,但令人困惑,因为program main use a_mod, only : c, inc_c implicit none call inc_c write(*,*) c end program main 不是a_modc的真正所有者。因此,您应该尝试inc_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

时尤其如此

答案 1 :(得分: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表示模块中声明的数量默认情况下导出。现在,您必须通过添加use语句,在public模块时显式声明要使哪些变量和子例程可用。 (也可以使用语法integer, public :: c = 10在一行中完成。)这种做法可以防止c_mod变量泄漏出b_mod,依此类推。

答案 2 :(得分: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的目的有用(如果真的有必要)。