変数と型

こんにちは、めのんです!

前回、前々回と退屈な話が続いたためかアクセス数が激減しています。
せっかく書いたブログなのでたくさんの方に読んでいただきたいという思いはあるのですが焦ってもしかたありません。
私は私にできることを精一杯やるだけです。

それでは早速本題に入ります。
今回のテーマは変数と型です。

PHPにも変数はありますし型もありますので、変数や型そのものの概念についての解説はとくに必要ないと思います。
ここではPHPとは違うCの変数や型の扱いを中心に解説していくことにします。

ところで、ここまで「変数」と書いてきましたが、正確にいうとCの場合は「オブジェクト」という呼び方になります。
いずれ別の機会に詳しく解説しますが、Cにはconst修飾子というものがあって、それを付ければ変更ができなくなります。
変更できないのに「変数」というのも変ですよね。
それだけの理由かどうかはわかりませんが、Cでは「オブジェクト」と呼ぶのが正確です。

オブジェクトの宣言

Cではオブジェクト(変数のことですね)を使うためには必ず宣言が必要になります。

オブジェクトの宣言を行うときはオブジェクトの型を指定しなければなりません。
PHPでは型は値に備わっているもので、変数自体は型を持っていませんでした。
ところがCではコンパイルの段階でオブジェクトの型が決まらなければならず、あとから変更することができません。

具体的なオブジェクトの宣言例を見てみましょう。

int x; // 初期値のないオブジェクト
long y = 123; // 初期値付きのオブジェクト

オブジェクトの初期値

上の例ではxとyの2つのオブジェクトを宣言しました。

xは初期値がないオブジェクトです。
初期値を指定しないとオブジェクトの値は不定になります。
値が不定というのは本当にどんな値が入っているか分からないということです。
「ゴミが入っている」という言い方をすることもあります。

一方でyは123という初期値を指定しています。
このように明示的に初期値を指定してあげると不定な値が入らないので安心ですね。

オブジェクトの型

ところでxやyの宣言では先頭にintやlongといったものが付いています。
PHPでも引数を型指定では同じように書くので、これが型だということは何となく想像が付いたのではないでしょうか?

int型というのはPHPにもあるように「integer」の意味で整数型を意味しています。
PHPでもそうでしたがCのint型も環境に依存します。
みなさんが使っているGCCの場合はint型は32ビットの符号付き整数を表します。

long型というのは「long int」がフルネームで、読んで字のごとく長い整数型です。
みなさんが使っているGCCの場合、CygwinやMinGW-w64ではint型と同じで32ビットの符号付き整数を、64ビットのLinuxやmacOSでは64ビットの符号付き整数を表します。

ほかにもいろんな型があるのですが今回はここまでにしておきます。

有効範囲

Cのオブジェクトには「有効範囲」という概念があります。
PHPにもローカル変数とグローバル変数の区別がありますが、大雑把にいってそれと似たようなものだと考えてください。

Cのオブジェクトは次のどれかの有効範囲を持ちます。

  • ファイル有効範囲
  • ブロック有効範囲
  • 関数原型有効範囲

本当はもうひとつ「関数有効範囲」というのがあるんですけど、これはgotoの飛び先になるラベルのためのものです(PHPにもgotoがありますね。PHPのgotoは関数の外でも使えますけど)。

「ファイル有効範囲」というのは関数の外でオブジェクトを宣言した場合の有効範囲です。
Cでは前方参照はできませんので宣言より前でオブジェクトを参照することはできませんが、そのことを除けば同じソースファイル内のどこからでも参照することができます。
もちろん、#includeで取り込んだソースコードからも参照することが可能です。

「ブロック有効範囲」というのは波括弧 {} で囲まれたブロックの中でだけ参照できます。
関数のブロックもそうですし、if文やswitch文など(このあたりの文はほぼPHPと同じです)のブロックもそうです。
単にブロックだけを書いた場合もこれに該当します。

「関数原型有効範囲」というのは関数の仮引数の有効範囲です。
一応ブロックの外なのでご丁寧に別の有効範囲になっています(笑)
PHPだと関数の仮引数もブロックの中で使い始めた変数も同じローカル変数ですよね。

以下に有効範囲を実際のコードで表してみます。

int x; // ファイル有効範囲

int func(int arg) // 関数原型有効範囲
{
  int x; // ブロック有効範囲

  {
    int y; // ブロック有効範囲
  }
}

1行目と5行目では同じ「x」という名前のオブジェクトを宣言しています。
この場合、ブロックの中では一番内側の有効範囲にいる「x」しか参照することができません。
ただし、ブロック有効範囲の宣言より前であれば外側のオブジェクトを参照することができます。
PHPのようにglobalを使ってグローバル変数(Cの場合はファイル有効範囲のオブジェクト)にアクセスすることはできませんので注意が必要です。

記憶域期間

有効範囲とちょっと紛らわしいかもしれませんが、Cのオブジェクトには「記憶域期間」という概念もあります。
記憶域期間というと難しく聞こえるかもしれませんが、要するにオブジェクトの生存期間(寿命)のことです。

ブロック内で宣言したオブジェクトは原則としてブロックから抜けると解放されてしまいます。
そのようなオブジェクトは「自動記憶域期間」を持っています。
関数の仮引数も自動記憶域期間を持っています。
PHPだとブロックの中だけで変数を使っても、実際に解放されるのは関数を抜けるときなのでCとはちょっと違います。

関数の外で宣言したオブジェクトや、static指定子を付けて宣言したオブジェクトは「静的記憶域間」を持っています。
PHPにも「static」はありますが、それと同じです。

もうひとつ「割付け記憶域期間」というのがあります。
これはmalloc関数などを使って自分でメモリーの割付けと解放を行う場合の記憶域期間です。
「Cでは自分でメモリー管理をしないといけない」とよくいわれますが、それはこの割付け記憶域期間のオブジェクトのことです。
自動記憶域期間や静的記憶域間のオブジェクトは勝手に解放されますからメモリー管理を自分でやる必要はありません。

まとめとして記憶域期間についても具体的なソースコードを挙げておきますね。

int x; // 静的記憶域間

int func(int arg) // 自動記憶域期間
{
  int y; // 自動記憶域間

  char *p = malloc(10); // 割付け記憶域期間
  free(p); // 割付け記憶域期間のオブジェクトは自分で解放する必要があります。
}

割付け記憶域期間の例も挙げましたが今はまだ分からなくてかまいません。

ちなみにC++11からはマルチスレッドが導入されたので「スレッド記憶域期間」というのもあります。
これについては詳しく触れませんので、ご興味のある方は調べてみてください。

以上で今回の解説を終わります。
次回は翻訳フェーズの解説を行います。
どうぞご期待ください!