[前へ]   [目次へ]   [次へ]

宣言、定義の正体(1)(C/C++)


今回から、基礎編へとランクアップです。
ここまでの54回分の知識は前提として進めますので、
分からなくなったり、自信がない人は入門編を読むことをお勧めします。


これまで、定義は変数と関数について書きました。
宣言についてはメインで解説したことがないので、初出のようなものですが、
宣言の概念というのは正体を知った状態の方がわかりやすいかと思うので、
こちらは後回しとします。

実質的な扱いは変数も関数も同じようなものなのですが、
まずはこれまで多用してきた変数をベースとして解説していこうと思います。

さて、今まで、「変数定義」と言えば、
「変数を新しく作って使えるようにする」ぐらいのイメージでいると思います。

実際、この講座も含め、大抵の入門書などにはそのように書いてあると思いますし、
確かに「変数を作って使えるようにしている」ので、間違ってはいません。

しかし、実はそれでは不完全なのです。
「定義」とはそんな曖昧な解釈でいてはいけない存在なのです。
この先に出てくるポインタを筆頭とする要素は、
この「定義」の理解が完全であることが前提になっています。

私は、「Cはポインタが難しい」だとか「ポインタでつまづく」だとかいうのは
「定義」を十分に理解しないままに使おうとするからだと考えています。
というわけで、今回からは「定義とは何か」を詳しくやっていきます。


さて、そろそろ始めます。
「定義」というのは、「〜とは〜である。」ということを決めるものです。
今までは、
int n;
等として「 n とは int型の変数 である。」みたいな使い方をしてきました。
これは、コンパイラが n という識別子(名前)をどう扱えばいいか、
というのを「定義」しているわけです。

しかし、「定義」の意味はこれだけではありません。
実行時にデータを実際に保存するための「実体」を作成する機能も持っています。


つまり、
int n;
という一文は、「 n とは int型の変数 である。」という定義と
それに対応して実際にデータを保持する「実体」の作成を同時に行う構文ということです。

また、
extern int n;
のように extern を付けると「変数宣言」となりますが、
この場合は「 n とは int型の変数 である。」という定義のみが行われ、
「実体」の作成は行われません。
「実体」が作成されないとデータを保持できないので、
宣言した変数は後に「実体」を作成する「定義」が行われない限り、リンクエラーになります。

ところで、「定義」は「宣言」を兼ねるということになっていることから、
「 n とは int型の変数 である。」というのはC/C++言語では「宣言」であり、
「実体」を作成する部分のみを指して「定義」と読むこともできます。



さて、C/C++言語のソースをビルドした後の実行可能ファイルには、
実は「変数名」とか「関数名」なんてのは残ってません。
これらは全てコンパイラが番号に書き換えて、番号としてのみ残されています。

にもかかわらずデバッガが変数名等を表示することができるのは、
デバッグ用にビルドしたときにはデバッグシンボル情報という
「どの番号がソース上でどんな名前だったか」という対応表が作られていて、
それを参照して元に戻しているからなのです。

なので、「 n とは int型の変数 である。」という定義は結局のところ
ビルド時までしか存在していない、つまりコンパイラに対する定義なのです。

一方、「実体を作成する」というのは実際にデータを格納するためにメモリを使用する時、
つまりビルド後の実行可能ファイルを実行する段階になってからしかできません。

そのため、「実体を作成する」定義は実行可能ファイルに命令として組み込まれていて、
実行する段になって「メモリを確保してデータを保存できるようにする」という命令として実行されます。


実はこの辺の区別というのは非常に重要なものがあり、
特にポインタ、C++の型変換に関する仕様などでは、二つの「定義」が明確に区別されていて、
その違いを見失う=即バグ決定 ぐらいの影響力を持ちます。

次回からはこの二つの定義がどのような関係にあるか、
また、C/C++言語の各所でどのように関わってくるかていう部分を重点的に解説していきます。


[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17