2008年10月29日水曜日

C 言語の話#2 char *const c; って何?

C 言語について,ふと思ったことや,調べてみたことなどを書くことにした.

今回は,const について.一般的な C 言語入門書で解説される const の使い方ってこんなんだった気がする.

float circle(float r) {
const float pi = 3.14159265;

return r * r * pi;
}


この場合は,円周率 pi が定数ですよってことを示すために,const を付けていることになる.メリットは,プログラマが勘違いして関数中で代入する間違いが避けられるとかいう話になるのかな.あとは,コンパイラによって最適化されやすくなる.(まあ,いまのコンパイラは賢いから,この情報が無くても最適化してくれると思うけど.)

現実的には,const は次のように使われていると思う.(Book は typedef 宣言で宣言された本の構造体への型ってことで.構造体のような大きなサイズの変数を値渡しすると,そのコピーに時間がかかるので,アドレス渡しが基本になるからね.)

int get_isbn(const Book *book) {
return book->isbn;
}


これは,Book 型の変数へのポインタを渡しても,内部でその値が書き換えられることはありませんよってことを示している.つまり,次のような処理は許されないんだよね.

int get_isbn(const Book *book) {
book->isbn = 1234567890; // コンパイルエラー

return book->isbn;
}


これの何がおいしいかというと,ひとつは開発者側のミスが無くなることなんだ.仕様上引数の値を変更する必要が無いとわかっているのであれば,インターフェースにあたる仮引数に const を付けることによって,関数の実装で間違って代入してしまうようなことが避けられる.もうひとつは,これが公開関数だった場合,ユーザ側が安心して関数を使えること.この関数にアドレス渡ししても,その値が更新されることが無いことが保証されているからね.

最後に,タイトルにあげた質問の答え.前述の Book で考えると次のようになる.

int get_isbn(Book *const book) {
book->isbn = 1234567890; // コンパイルエラーにならない
book = NULL; // コンパイルエラー

return book->isbn;
}


つまり,book の示すアドレスの変更を不可能にするのだ.(だから,const Book *book の場合は,book = NULL; はコンパイルエラーにならない.)ちょっと見慣れないかんじだと思うので,しっくり来ないかもしれない.タイトルにまでしていてあれだけど,ほとんど使う機会はないので無視してしまっていいと思う.(僕としてはそういう認識.いや,使う機会がすごくあるという人は,コメントに書いていただけると助かる.)

もちろん,こういう書き方もある.まあ,僕は使うこと無いけど.
int get_isbn(const Book *const book) {
book->isbn = 1234567890; // コンパイルエラー
book = NULL; // コンパイルエラー

return book->isbn;
}


ということだね.参考になったかなぁ.

参考文献:
平林雅英.新ANSI C言語辞典,技術評論社,1997.

0 件のコメント: