変数 (プログラミング)

プログラミングにおいて、変数(へんすう、variable)とは、プログラムソースコードにおいて、扱われるデータを一定期間記憶し必要なときに利用できるようにするために、データに固有の名前を与えたものである。 一人一人の人間が異なる名前によって区別されるように、一つ一つの変数も名前によって区別される。これにより、複数のデータを容易に識別することができる。変数名は一般に(字句的[1]には)識別子である、ないし、変数の識別子のことを変数名という。一般に、変数が表しているデータをその変数の(あたい)という。

目次

変数の宣言と代入と参照編集

プログラムにおいて変数を扱うための主要な操作は、宣言・代入・参照の三つである(これも異なるかもしれない)。プログラミング言語によって変数の扱い方は多少異なるので、ここでは一般的な事柄を述べるにとどめ、実際のプログラミング言語の仕様(規格票)の表現とは、いずれも一致しないかもしれない(一般に、言語によって用語の意味も異なる)。

宣言編集

プログラムの中でどのような名前の変数を用いるのかを、プログラミング言語の文法にのっとって明確に示すことを変数の宣言(せんげん)という。

いくつかのプログラミング言語では、変数を宣言する際にその名前だけでなくそのデータ型も指定する必要がある。 これにより、各変数が扱うことのできるデータの種類を制限できる。一般に、データに対して行える処理はデータ型によって異なるので、データ型を厳密に検査することで、誤ったプログラムを書いてしまうことを防止するのに役立つ。

また一部のプログラミング言語では、型推論といって、プログラムで変数の型を明示しなくても、型システムにより自動的に型を推論する機能がある。型推論は、型を明示しなくてもよくするため(この場合、推論の結果がその変数の型になる)だけではなく、式に対して(「変数に対して」ではない)明示された型が適切か否かを確認するためにも使われる。まともな型推論では、代入が一度にまとめて行われないような変数(例えば、関数の仮引数は、省略時のデフォルト値があるような場合もあるが、普通はそうではない)に対しても推論を行うことができるが、言語によっては変数の宣言と代入が一度にまとめて行われることが前提となっているようなものを「型推論と呼んでいる」場合も多い。

代入編集

宣言した変数に対して実際にデータを関連付けることを代入(だいにゅう)という。

プログラミング言語によっては、変数の宣言と代入を一度にまとめて行うことができる。 変数を宣言せずにいきなり代入できる言語もあるが、これは宣言されていない変数に対して処理系が自動的に宣言を補ってくれていると考えることが出来る。 ある変数に対して初めて行う代入は、特に初期化(しょきか)という。

多くの手続き型言語では、変数は複数回代入をすることができる。すでに代入を行った変数に改めて代入をすると、その変数とそれまでのデータとの関連はなくなり、新しいデータと改めて関連付けされる。 関数型言語では、一つの変数には一度しか代入できないものも多い。このような言語では、宣言と初期化を一緒に行うのが一般的であり、また、一つの変数が常に同じ値を持つ(値が変化しない)ことが保証される。(参照透過性

参照編集

その変数に代入したデータを利用することを、変数の参照(さんしょう)という。

一度も代入を行っていない、つまり初期化していない変数を参照することは意味を成さず、不正である。 しかし一部のプログラミング言語では、変数を宣言した段階で、自動的に何らかのデータが変数に関連付けられる。このような言語では、初期化を明示的にプログラムしないまま変数を参照できる。

スコープとエクステント編集

変数のスコープ(scope: 可視範囲)とは、変数がソースコード内のどこから「可視であるか」ということである。一方、変数が持っているその内容との対応が、再代入などが無ければ「いつまで保持され続けるか」が、変数のエクステント(extent: 生存期間、存在期間、寿命)である。

以上のように全く違う概念であるにもかかわらず、ほとんど全てのプログラマはスコープとエクステントを混同しており、わずかなプログラマだけが識別しているようである。たとえば、スコープはその変数のエクステントを規定する(要因の一つ)と誤解している。

スコープ編集

変数はその変数に対して定められたソースコードの特定の範囲内からしか「見えない」。すなわち、その変数が使用可能な範囲が、その変数のスコープ(scope: 可視範囲)である。例えば C では、関数の中で宣言した変数はその関数の中でのみ使用できる。これにより、関数内部の処理とは関係のないところから変数を使用されるのを防ぐことができる。また、異なる関数で宣言した変数に対して同じ名前を付けることもできる。一般に、変数に限らず、なんらかの名前について「名前空間を区切るもの」が「スコープ」である(たとえば構造体のメンバ名は、各構造体ごとに名前空間を持つ[2])。

一つのスコープにおいて同じ名前を複数の違うものに使うことは、許されていないことが多い。あるいは許されている場合は、後から現れたものによって、そこから後では前のものは掩蔽(シャドウ)されるという規則の場合もある。

さらに、スコープが入れ子になっている場合にも似たようなケースがある。たとえば、C言語の「グローバル」「ソースファイルごと」「ブロック内(ローカル変数)」というスコープは、それぞれ入れ子になっていて、かつ、内側からは外側のスコープにある名前が見える(内側からは外側のスコープにある名前は見えない、というような名前空間もある)。そのような時、外側に既にある名前と同じ名前は内側では使えないという規則のこともあれば、内側で同じ名前を使うと、外側のものはシャドウされるという規則の場合もある。

プログラミング言語には多くの種類のスコープがあるが、詳細については「スコープ」の記事を参照のこと。

以上のように、スコープは実行時のものではなく、基本的にソースコード上で静的に定まるものである(「動的スコープ」という例外もあるが[3])。

エクステント編集

以上のようにスコープは変数に限らず、プログラミング言語などの言語における、名前そのものの可視範囲についての概念である。それに対し、エクステント(extent)は変数とその中身(オブジェクト[4])の対応付けについての概念である。

変数のエクステントとは、プログラムの実行時に、その名前とそれが指すオブジェクトという対応付けが、いつ始まり、(再代入などが無い限り)いつまで保持されるか、ということである。

グローバル変数のエクステントは、プロセスの生成時か最初の代入時に始まり、プログラムかプロセスの終了時まで、というプログラミング言語が多い。

C言語の場合、関数の仮引数や、ローカル変数でstatic修飾が無い場合(ほとんど使われていないが、autoというキーワードがあるにはある)、エクステントはその関数呼出しから抜けるまでである。これは、C言語では関数呼出しから一旦抜けてしまうと、そこに戻ってくることは無い(setjmp/longjmp(en:Setjmp.h)を使えば不可能ではないが、「深い方に飛ぶ」ジャンプは禁止されている)からである。

クロージャなどにより、その変数へのアクセスがその後もあるかもしれない場合は、その関数呼出しを抜けてもその対応付け(束縛、bindingなどとも)は保持されなければならない。クロージャないしそのようなものがある言語では、そのためにローカル変数でもエクステントは(アクセスされる可能性がある限り)延長される。そのようなエクステントをinfinite乃至indefiniteのエクステント(訳して、無限の、あるいは、無制限の存在期間、など)という。

C言語の関数のローカル変数でstatic修飾を付けると、グローバル変数と同様のエクステントになる(なお、C言語のグローバル変数へのstatic修飾は、エクステントではなくスコープの制限になる。これは単にstaticという同一のキーワードを、文脈から区別が可能だから流用しているというだけで、それぞれの意味は全く違う(後者はfilescopeといったような別の表現にするのが本来は適切だっただろう)。この流用が、おそらくスコープとエクステントを多くのプログラマ[5]が混同する原因の一つである)。

編集

  1. ^ lexically
  2. ^ ごく初期のC言語(UNIXバージョン6の頃)では違うが。
  3. ^ 「動的スコープ」という用語自体が変である、という指摘がある http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html
  4. ^ いわゆるオブジェクト指向のオブジェクトではなく、プログラミング言語で値を表すものや、メモリにあるもの(メモリオブジェクト)などといったものの総称である。
  5. ^ 例えばPHPのマニュアルに「Another important feature of variable scoping is the static variable. A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope.」( http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static )とあるのは、エクステントについて議論しているのにエクステントの語が無く、この記述では混同されているものと見られる。

関連項目編集