next up previous
Next: About this document ... Up: 計算天文学 II Previous: 4 関数と制御構造

Subsections


5 関数の宣言と「スコープルール」

以下に書くことは、必ずしも本質的ではないが実際にプログラムがどう 動くか、あるいはどうやって書くかを理解するには結構重要なことである。

5.1 関数のプロトタイプ宣言

今日やった例では、

double f(x)
{
...
}
void bisection(...)
{
   ... = f(...);
}
int main()
{
...
   bisection(...);
}

といった風に、「使う関数はあらかじめその前に定義されている」とい う形になっている。で、例えば引数の対応が間違っているとコンパイラ がチェックしてくれる。これでうまくいくのはまあいいような気がするわけ だが、良く考えてみるとちょっと変である。

というのは、使うすべての関数をプログラ ムの中で定義できるわけではないからで ある。このために使っているのが、「プロトタイプ宣言」と呼ばれる機 能である。プロトタイプ宣言は、例えば以下のような形をしている。

 void bisection(double & xmin,
               double &  xmax,
               double eps);
つまり、関数の最初のところだけ書いて、その後に実行部をつけないで セミコロンを書いておしまいにしたものである。これは、「この名前の 関数はこういう引数をもらって、こういう値を返します」ということを コンパイラに教える役割をはたしている。

この、プロトタイプ宣言というものは、要するにある関数について、 「それが外からどう見えるか」を規定している。えらそうにいえば「イ ンターフェース」を決めているということもできる。

Fortran では、言語仕様の中には特にこのようなチェックについて規定してい るところはないので、引数の型や数が間違っていてもコンパイラはエラーを検 出してくれないことが多い。

また、 C 言語の場合、プロトタイプ宣言が間違っていた時にかならずしもそ れが発見されるとは限らなかった。 C++ の場合には引数が違うものは違う関 数になるので、間違ったプロトタイプ宣言があるとリンク時に失敗するので発 見できる。

これは C++ の重要な機能、「関数のオーバーロード」(多重定義)というも のの結果である。例えば Fortran では、

subroutine foo(x)
real x
...
end
というものがあった時に、
subroutine foo(x)
integer x
...
end
というふうに引数は違うが名前は同じ関数を定義することはできない。ところ が、C++ では
void  foo(double x){}
void  foo(int x){}
は別物として扱われる。

もちろん、だからといって必要もないのに同じ名前を使うことは混乱を招くの で避けるべきだし、また引数の型が違うだけで処理の内容が同じならばテンプ レート(多分後で説明する)を使って汎用の関数を作るべきであろう。

5.2 スコープルール

スコープというのは何かというと、例えば変数であれば、宣言した変数 をどこで使うことができるかということである。宣言の有効範囲という こともできる。例えば

double f(x)
{
    double y;
    ...
}
int main()
{
    double y;
    .....
}
というプログラムを考えてみる。ここでは、 f(x) の中の変数 y と、 main の中の変数 y は全く別物であって、例えば f(x) の中で y を書き 換えたらその結果が main に伝わったりはしない。物理的には、これは、 メモリの違う場所におかれるということを意味している。

こういうことができるのは、ある関数の中で宣言した変数は、その関数 のなかでだけ有効だからである。その関数以外の関数が、勝手に変数を 書き換えたりはできない。これは、不便なような気がするかもしれない が、大きなプログラムを作るという場合とか、たくさんの人が協力して プログラムを作る時とかには非常に重要な機能である。

ただし、抜け道も準備されている。例えば

double y;
double f(x)
{
    ...
    y = ...
}
int main()
{
    f(x) = ...
    cout << y << endl;
}
といったように、「関数の外」で変数を宣言することもできる。この場 合には、変数宣言の下に出てくるどの関数でも、この変数を使うことが でき、それらはみな同じものである。したがって、上の例のように、fの 中でその変数に代入し、 main の中でその値を見れば、fで入れた値が出 てくることになる。

Fortran ではこのようなことを実現するのには COMMON BLOCK を使う必要があっ たが、 C/C++ では手軽に関数間で変数の共有ができる。これは利点でもあり 欠点となることもある。

今日はこれくらい。次回は C++ 文法事項の続き。

5.3 練習

今日出たプログラムを実際に書くなり cut & paste するなりして動かしてみ ること。



Jun Makino
平成16年10月18日