16 モジュール
- 16.1 モジュールの定義方法と利用方法
- 16.2 ソースコード内のモジュールの記述位置
- 16.3 共通ブロックの代わりにモジュールを利用する
- 16.4 定数集としてモジュールを利用する
- 16.5 手続集としてモジュールを利用する
- 16.6 参照許可について
- 16.7 ★ 練習課題:2つの整数の足し算と引き算を行うモジュール
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 モジュール内の名前を別の名前で参照する方法
手続名や変数名が重なってしまう場合など、モジュール内の変数名や手続名を別の名前で参照したい場合があります。 例えば下記のように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つの整数の足し算と引き算を行うモジュールを作成して下さい。 足し算を行うモジュール関数と引き算を行うモジュール関数を一つのモジュールの 中に作成して、メインプログラムから呼び出して下さい。処理手順例
-
モジュールを利用する旨を宣言する
例)
use two_integers ! two_integers というモジュールを利用することを宣言 -
変数の宣言を行う
例)
integer :: a = 2, b = 3 -
足し算を行う関数を呼び出して結果を出力する
例)
print *, "a + b =", add(a,b) -
引き算を行う関数を呼び出して結果を出力する
例)
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つの整数の足し算と引き算を行うモジュールのプログラム例
前へ 上へ 次へ
