メインメニューを開く

差分

グローバル変数

6,992 バイト追加, 2015年3月9日 (月) 02:46
ページの作成:「'''グローバル変数'''(英語: global variable)とは、プログラミングにおいて全てのスコープからアクセスできる変数...」
'''グローバル変数'''([[英語]]: global variable)とは、[[プログラミング]]において全ての[[スコープ]]からアクセスできる[[変数]]のことである。
日本語では大域変数などと呼ばれるが、相手が[[プログラマー]]であれば[[プログラミング言語]]を問わずほぼ「グローバル変数」で意味は通じる。
対する語は[[ローカル変数]]である。

「[[スコープ]]」の項目も参照。

==概要==
===欠点===
一般にグローバル変数は、その非局在的な性質ゆえに好ましくない実践だと考えられている。すなわちグローバル変数は潜在的にどこかで変更される可能性があり、また[[プログラム]]の一部はそれに依存してしまう恐れがあるからである。グローバル変数はそれゆえ相互依存を生み出す無限の可能性を持っており、相互依存が高まることは複雑性を増大することにつながる。

また、純粋なグローバル変数ではないが、[[オブジェクト指向]]における[[クラス変数]]などは、すべてのスコープからはアクセスできないが[[関数]]の動作に影響を与える準グローバル変数と言える。これらが連鎖することで「クラスの中で使われてるクラスの中で使われているクラスを完全に把握していないとどういう動作になるかわからない」という、単純なグローバル変数よりも恐ろしい状況に陥る。この悪夢を[[副作用]]という。

[[ダイナミックリンクライブラリ]]のような多くのシステムは他のモジュールにあるグローバル変数の参照を直接サポートしないため、グローバル変数が多用されている[[コード]]を分割して再利用ライブラリにすることは非常に困難である。また、グローバル変数が他のローカルまたはオブジェクトスコープ変数として代用するには危険な名前を作るために起こる名前問題を導いてしまうことがある。グローバル変数と同じ名前のローカル変数は、一般にそのローカル変数のスコープにおいてグローバル変数を隠匿する。そのため、さらにコードの理解を困難にする。グローバル変数への値の書き込みは理解と予測を難しくする[[副作用]]を生み出す。

グローバルなどの利用は[[ユニットテスト]]を目的とするコード分割をより難しくする。それゆえ、それらは直接にコードの質の低下を助長する。

===利点===
しかしグローバル変数が適する状況もある。たとえば様々な[[関数]]を通して継続的によく使われる変数を[[引数]]として渡すことを避けるために使用できる。また、並列実行する[[スレッド]]や[[プロセス]]のように、呼び出し側と被呼び出し側の関係を持たない[[コード]]同士でセクション間の情報を受け渡すためにも広く使われる。

また、各々の[[ファイル]]が暗黙の名前空間([[無名名前空間]])を定義するような[[言語]]では、グローバルな名前空間を持つ言語に見られる問題の多くが解消されているが、一部の問題は適切な[[カプセル化]]を行わなければ解決できない。[[ミューテックス]]のような適切なロック無しにグローバル変数を使用している[[コード]]は、保護メモリ内の読み出し専用値以外は[[スレッドセーフ]]ではない。

==実装例==
[[C++]]におけるグローバル変数の例:
<source lang="cpp">
#include <iostream>

int global = 3 ; // これはグローバル変数。

void ChangeGlobal ()
{
global = 5 ; // 関数でグローバル変数を書き換え。
}

int main (int argc, char *argv [])
{
std::cout << global << std::endl ; // もう一つの関数でグローバル変数を参照。
ChangeGlobal () ;
std::cout << global << std::endl ;
return 0 ;
}
</source>
この変数はグローバルなので、main以外の全ての関数にそれを引数として渡す必要がない。グローバル変数はプログラム内で、全ての関数に属する。

この出力結果は、以下のようになる:
3
5

===グローバル変数の問題点===
グローバル変数を使用すると、[[ソフトウエア]]の[[ソースコード]]を理解することが困難になる。グローバル変数の値は[[プログラム]]のどこからでも変更できるため、グローバル変数がどのように使用されているか理解するためには、[[プログラム]]全体を把握しなければならないからである。

以下にグローバル変数により難解になる例を示す:
<source lang="cpp">
int a, b, c ; // グローバル変数宣言

int main (int argc, char *argv [])
{
FunctionA () ; // グローバル変数cを書き換える
FunctionB () ; // グローバル変数cを元にグローバル変数aを書き換える
FunctionC () ; // グローバル変数a, cを元にグローバル変数bを書き換える
return 0 ;
}
</source>

===ローカル変数で書きなおし===
上記を[[ローカル変数]]を用いて書きなおした例:
<source lang="cpp">
int main (int argc, chra *arg [])
{
int c = FunctionA () ; // ローカル変数cを書き換える
int a = FunctionB (c) ; // ローカル変数cを元にローカル変数aを書き換える
int b = FunctionC (a, c) ; // ローカル変数a, cを元にローカル変数bを書き換える
return 0 ;
}
</source>
[[ローカル変数]]を用いた例ではどの[[変数]]が、どの関数呼び出しに作用し、どの関数呼び出しの結果を保持しているかは一目瞭然である。
対して、グローバル変数を使用した例では、関数の呼び出し側だけを見てどの関数がどの変数に影響を与えるかを判断することはできない。

また、[[ローカル変数]]を用いた例では関数の呼び出し順序を入れ替えることは引数と戻り値だけ意識すれば良く容易であるのに対して、グローバル変数を用いた例ではグローバル変数の作用を全て把握する必要があるため困難である。特にこの困難度合いは、グローバル変数の数とグローバル変数を操作する可能性のある関数の数に比例する。

== 関連項目 ==
*[[変数]]
*[[静的変数]]
*[[クラス変数]]
*[[Singleton パターン]]
*[[副作用]]
*[[オブジェクト指向は愚かな考え。排便メソッドを実装した人間クラスから美少女クラスが作れない。]]
*[[Bjarne Stroustrup インタビュー]]

==参考文献==
{{reflist}}

{{stub}}

{{DEFAULTSORT:くろおはるへんすう}}
匿名利用者