関連情報

Fortran Builder
ナビゲーション:前へ   上へ   次へ

16 モジュール

Fortranにはモジュールと呼ばれる非常に便利な機能があります。 モジュールを利用すると、変数、定数、型、手続、インターフェース定義などをまとめる事ができます。 プログラムの保守性などの観点から、モジュールの利用は強く推奨されています。

16.1 モジュールの定義方法と利用方法

モジュールは以下のように定義します。
  module モジュール名
    [宣言部]
 [contains
    モジュール副プログラム部]
  end [module [モジュール名]]

定義されたモジュールを別の場所から利用する場合には以下の例のように use 文を用います。 use文は各プログラム単位の最初に書きます。(program行、module行、外部subroutineおよび関数の後)

  program main
    use mymod
    implicit none   ! implicit noneはuse文の後に書きます
    ...

以下に非常に短いモジュールの一例を示します。

[ short-module.f90 ] - 短いモジュールのサンプル

module my_data
  implicit none   ! ここでも必要です
  integer,parameter :: my_age = 20
end module my_data

program short_module
  use my_data
  implicit none
  print *, "I am", my_age, "years old!"
end program short_module

出力例:
 I am 20 years old!

16.1.1 モジュール内の一部のデータのみを参照可能とする方法

モジュール内の一部のデータのみを参照可能にしたい場合には USE文において ONLY句が指定可能です。 以下に例を示します。

[ only.f90 ] - ONLY句を用いるサンプル
module my_constants
  implicit none
  real,parameter :: pi = 3.1416, e = 2.7183
end module

program only_example
  use my_constants, only: pi
  implicit none
  print *, pi
  !print *, e   ! piのみが参照可能になるのでこれはエラーとなる
end program

16.1.2 モジュール内の名前を別の名前で参照する方法

手続名や変数名が重なってしまう場合など、 モジュール内の変数名や手続名を別の名前で参照したい場合があります。 例えば下記のように二つのモジュールがあり、そのそれぞれで同じ名前の定数が存在した場合を考えます。
module apple
  implicit none
  integer,parameter :: listPrice = 150
end module
module orange
  implicit none
  integer,parameter :: listPrice = 80
end module

このように同じ名前が重なってしまっている場合などに参照する際の名前を別途指定(仮称指定)することができます。

  use モジュール名, ローカル名 => モジュール内での名前 [, ...]

以下に上記2つのモジュールのそれぞれの listPrice を別の名前で参照する例を示します。

program rename
  use apple, applePrice => listPrice
  use orange, orangePrice => listPrice
  implicit none
  print *, "Price of apple is", applePrice
  print *, "Price of orange is", orangePrice
end program rename

実行結果例:
 Price of apple is 150
 Price of orange is 80

16.2 ソースコード内のモジュールの記述位置

モジュールはモジュールをuse文で利用するソースコードが書かれているファイルと 同じファイルに記述することも可能ですが、別のファイルに分けて記述することも 可能です。モジュールはプログラム単位の一つなので、モジュール毎に別ファイルに ソースコードを記述することも可能です。

16.2.1 同一ファイル内のモジュール利用する場合

同一ファイル内のモジュールを利用(use)する場合、利用される側のモジュールは そのファイル内のより先頭に近い場所に記述されていなければなりません。(Fortran 標準ではそのような決まり事はありませんが、実質、多くのコンパイラ環境において そうでなければなりません)
例)
module mod1
...
end module mod1

program main
  use mod1     ! mod1は同一ファイル内でここより上ににあるのでこの記述はOK
  use mod2     ! mod2は同一ファイル内でここより下にあるのでこの記述はNG
...
end program main

module mod2
...
end module mod2

16.2.2 別ファイルのモジュールを利用する場合

モジュールを複数のファイルに記述する場合に、use文で指定するモジュールを含む ファイルが先にコンパイルされている必要があります。例えば以下に示すようなケース ではmod1.f90 --> mod2.f90 --> main.f90 の順にコンパイルする必要があります。 順番を間違えますと、モジュールが見つからないなどのエラーが発生します。
mod1.f90
module mod1
  ...
end module mod1


mod2.f90
module mod2
  use mod1   ! mod1を使う指定
  ...
end module mod2


main.f90
program main
  use mod2   ! mod2を使う指定
  ...
end program main

(補足)今日の多くのFortranコンパイラ環境においてモジュールは含むファイルを コンパイルすると、オブジェクトコード(*.o, *.obj等)が作成されると共に、 モジュール中間ファイル(*.modなどの拡張子が利用される)が作成されます。 この中間ファイルにはモジュールを利用する側のソースコードをコンパイル際に 必要な各種情報が含まれています。これにより利用される側のモジュールが 先にコンパイルされている必要性が出てきます。

16.3 共通ブロックの代わりにモジュールを利用する

Fortranの古き悪しき機能に共通ブロックというものがあります。 これはサブルーチン、関数、メインプログラム間でデータの共有を 行うための1つの方法です。共通ブロックは多くのバグの温床となるものですので ここではサブルーチン、関数、メインプログラム間でのデータの共有を モジュールを使って行う例を示します。

[ common-module.f90 ] - 共通ブロックの代わりにモジュールを利用するサンプル
! 共有データを含むモジュール(ここではmy_data)を定義する
module my_data
  implicit none
  real weight, height
end module my_data

subroutine input_weight()
  use my_data     ! my_dataを使うという指定
  implicit none
  print *, "Enter Weight:"
  read *, weight
end subroutine input_weight

subroutine input_height()
  use my_data     ! my_dataを使うという指定
  implicit none
  print *, "Enter Height:"
  read *, height
end subroutine input_height

program common_module
  use my_data     ! my_dataを使うという指定
  implicit none
  call input_weight
  call input_height
  print *, "Weight =", weight
  print *, "Height =", height
end program common_module

出力例:
 Enter Weight:
60
 Enter Height:
167
 Weight =  60.0000000
 Height =   1.6700000E+02

16.4 定数集としてモジュールを利用する

よく利用される定数をモジュール内で指定し、複数の場所から利用することが可能です。 これにより、プログラムの保守性が向上します。

[ const-module.f90 ] - 定数集としてモジュールを利用するサンプル
! よく利用される定数をモジュール内に定義する
module maths_constants
  implicit none
  double precision,parameter :: pi = 3.141592653589793238d0
  double precision,parameter :: halfpi = pi/2d0
end

program const_module
  use maths_constants   ! 使いたい定数を含むモジュールを指定
  implicit none
  print *, pi
end program const_module

出力例:
   3.1415926535897931

16.5 手続集としてモジュールを利用する

モジュールにはモジュール手続を含めることができます。 これにより良くつかわれる手続をまとめることができます。 モジュール手続は以下の例で示される通り、contains文の後に 記述します。

[ procedure-module.f90 ] - 手続集としてモジュールを利用するサンプル
module matrix_operations
  implicit none
contains    ! contains以降にモジュール手続を記述する
  subroutine mat_print( a )    ! 行列を出力するサブルーチン
    integer,dimension(:,:),intent(in) :: a
    integer :: i, j
    do i = lbound(a,1), ubound(a,1)
      do j = lbound(a,2), ubound(a,2)
        write (*, '(I3)', advance='no') a(i,j)  ! 改行しない指定
      end do
      write (*,*)   ! 改行
    end do
  end subroutine
end module matrix_operations

program procedure_module
  use matrix_operations
  implicit none
  integer,dimension(2,3) :: v
  v(1,1) = 10
  v(2,1) = 20
  v(1,2) = 30
  v(2,2) = 40
  v(1,3) = 50
  v(2,3) = 60
  call mat_print(v)
end program procedure_module

出力例:
 10 30 50
 20 40 60

16.6 参照許可について

モジュール内のデータ要素はモジュール外からの参照を許すか否かを指定することができます。 この指定を行うには型宣言文で参照許可属性を付加するか、もしくは参照許可宣言文により指定するかのいずれかの方法で行い、PRIVATEもしくはPUBLICのいずれかを指定することにより行います。 参照許可について何も指定を行わない場合は「参照可能である」(PUBLIC)事になります。
【参照許可属性】
  型指定子, publicもしくは private :: データ要素宣言並び

例)
module mod
  implicit none
  integer, public :: a, b, c
  integer, private :: x, y, z
...
end module mod

【参照許可宣言文】
  public もしくは private [[::]参照対象並び

上記と同じ事を宣言する例)
module mod
  implicit none
  integer a, b, c
  integer x, y, z
  public :: a, b, c
  private :: x, y, z
...
end module mod

上記例では a, b, c はモジュール外部からアクセス可能ですが、 x, y, z はモジュール内部からのみアクセス可能で外部からはアクセスできません。

モジュール手続の参照許可を指定するには、モジュール宣言部で参照許可宣言文を用います。 以下に例を示します。

【モジュール手続の参照許可を指定する例】
module mod
  implicit none
  private abc           ! このように参照許可宣言文で手続名を指定する
  public calc           ! モジュール外から参照可能なのは calc のみ
contains

  ! abcはモジュール内でのみアクセス可能
  subroutine abc()
    ...
  end subroutine abc

  ! calcはモジュール内外からアクセス可能
  subroutine calc
    ...
  end subroutine calc
end module mod

以下はサブルーチン init と calc がモジュール外部よりアクセス可能となっていて、 変数 numIteration 及び サブルーチン showNumIteration はモジュール外部には公開されていないというサンプルです。

module mod
  implicit none
  integer,private :: numIteration  ! モジュール内でのみ利用可能
  private showNumIteration         ! モジュール内でのみ利用
  public init, calc                ! モジュール外から参照可能
contains
  subroutine showNumIteration()
    print *, "Number of iteration is", numIteration
  end subroutine showNumIteration
  subroutine init()
    numIteration = 0
  end subroutine init
  subroutine calc
    numIteration = numIteration + 1
    call showNumIteration()
  end subroutine calc
end module mod

program access_example
  use mod
  implicit none
  integer i
  call init
  do i=1, 5
    call calc
  end do
end program access_example
[ access.f90 ] - モジュールでの参照許可を示すプログラム例

16.7 ★ 練習課題:2つの整数の足し算と引き算を行うモジュール

2つの整数の足し算と引き算を行うモジュールを作成して下さい。 足し算を行うモジュール関数と引き算を行うモジュール関数を一つのモジュールの 中に作成して、メインプログラムから呼び出して下さい。

処理手順例

  1. モジュールを利用する旨を宣言する
     例)use two_integers  ! two_integersというモジュールを利用することを宣言
  2. 変数の宣言を行う
     例)integer :: a = 2, b = 3
  3. 足し算を行う関数を呼び出して結果を出力する
     例)print *, "a + b =", add(a,b)
  4. 引き算を行う関数を呼び出して結果を出力する
     例)print *, "a - b =", subtract(a,b)

モジュールの骨組み例

module two_integers
  implicit none
contains
  function add(a,b)
    ...   ! ここに引数の宣言や処理を記述する
  end function add
  function subtract(a,b)
    ...   ! ここに引数の宣言や処理を記述する
  end function subtract
end module two_integers
実行例:
 a + b = 5
 a - b = -1
[ kadai-mod-two-integers.f90 ] - 2つの整数の足し算と引き算を行うモジュールのプログラム例


ナビゲーション:前へ   上へ   次へ

Results matter. Trust NAG.
Privacy Policy | Trademarks