わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

constの使い道

授業では,「constという型修飾子がつくと,対象となるオブジェクトの値を変えることができない」と言いましたが,これだけではconstの有用性を理解するには不十分です.
実用上,constが使用されるのは,次の2つのケースです.

  1. 文字列(を指し示すポインタ)を引数にとる関数で,関数の中では,その文字列を書き換えないとき
  2. 型と有効範囲を含め,定数を定義するとき

例えば,ライブラリ関数のstrcpyは,第1引数はchar *型ですが,第2引数はconst char *型です.ということで関数を呼び出すと,第1引数に渡す文字列領域は書き換えられるけど,第2引数については書き換えられない*1のだな,と想像できます.
なお,char *型のポインタ値を,const char *型のポインタ変数に代入することには何の問題もありません.型キャスト(明示的な型変換)をする必要もありません.「引数の受け渡しは,実引数から仮引数へのコピーである」ことと合わせて考えると,「実引数にはconstをつけておかなくてよい」ということになります.
逆に,const char *型のポインタ値(たいていはポインタ変数)を,char *型のポインタ変数に代入をしようとすると,コンパイル時に警告が出ます.型キャストをすれば,警告が出なくなりますが,そもそもそういう代入をしないよう,プログラムを見直すべきでしょう.
ポインタの代入については,「constなしのポインタ値を,constありの変数に代入できる.その逆は不可」と覚えておくといいでしょう.
constを用いた別の使い方として,定数の定義があります.伝統的な教え方では,「定数はマクロ(#define文)で」なのですが,#define文による前処理指令はソースコードの書き換えなので,ときには,その定数値の型が(主にプログラマやメンテナにとって)分からないことになります.さらに,#define文はファイル全体に影響しますので,「範囲を限って使用したい定数」にしたければ,範囲の終わりに#undef文を書かないといけないなど,不便です.
変数として定義すれば,値に,型を付随させることができます.そしてconstをつけることで,値を変更できない変数,したがって,定数となります.ローカル変数として定義すれば,有効範囲も限定されます.
このconstの使い方は,Javaで,変数にfinal修飾子をつけるのに似ています.

*1:ただし,自作関数でconst char *pといった形で仮引数を定義したとき,関数の中でp++;のように,仮引数pの値,つまり指し示す先を変更することはできます.これは,pの型は「const charのポインタ」なのであって,「char *にconstをつけたもの」ではない,と思うといいでしょう.「(*p)++;」はできません.*pがconst char型のオブジェクトなので,その値を変更することはできないのです.