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.

2008年10月28日火曜日

C言語の話#1 仮引数での配列添字演算子はシンタックスシュガー

久しぶりの更新で,C言語の話.最近までちゃんと知らなかったので,備忘録的にエントリにしてみた.

配列を引数にとる関数の定義は,次のようなかんじになると思う.
void f(int a[])
{
/* 処理 */
}

また,次のようにかいても問題ない.
void f(int *a)
{
/* 処理 */
}

というか,前者は後者のシンタックスシュガーでしかない.
int a[8];
a = NULL;

は,コンパイルエラーになるが,
void f(int a[]) {
a = NULL;
}

は,コンパイルエラーにならないことから理解できる.

となると,次のような2次元配列の場合が気になる.
void f(int a[][8])
{
/* 処理 */
}

これは,次の記述と同じ意味になる.
void f(int (*a)[8])
{
/* 処理 */
}

予想と違ったという人も結構いると思う.int *a[8]ではなくint (*a)[8]なのだ.ちなみに,前者は,int型へのポインタの配列で,後者は,int型の配列へのポインタだ.

さて,なんでこんなことになってんだろう.これについては,次のプログラムを見てほしい.
int a[8];
f(a);

何ら変哲のない,配列を関数に渡すプログラムだ.しかし,このとき関数に渡されるのは,本当に配列だろうか?実は,アドレスでしかない.配列として確保された領域の先頭アドレスだ.(知っていると思うけど,aと&a[0]が同じ.)つまり,配列を渡しているというわけではないのだ.

そう考えると,次のような2次元配列のときの説明も容易だ.
int a[4][8];
f(a);

渡しているのは,2次元配列の先頭アドレスである.(aとa[0]と&a[0][0]が同じ.)しかし,2次元配列であるので,列の要素数を知らなければ,2次元配列としてアクセスができないのだ.(列の要素数がわからないと,次の行がどの番地から始まるのか計算できない.)もちろん,2次元以上の多次元配列にも同様のことがいえる.

ということで,こんな風にまとめたわけだけど,間違ってそうで怖いなwC言語に超詳しい人ってざらにいるしw間違ってたら教えてください(*- -)(*_ _)ペコリ

参考文献:
B.W.カーニハン,D.M.リッチー.プログラミング言語C 第2版, 共立出版, 1989.
平林雅英.新ANSI C言語辞典,技術評論社,1997.

2008年10月26日日曜日

LaTeX に UTF-8 な TeX ファイルを食わせる方法

エンコーディングを UTF-8 にした TeX ファイルをコンパイルすると文字化けしてしまう.その解決策.

$ platex --kanji=utf8 sample.tex


というふうに,kanji オプションをつけるだけ.MacPorts からインストールした LaTeX はこれでいけた♪

2008年10月2日木曜日

iPod shuffle 買った♪

iPod shuffle を買った♪カラーは,(PRODUCT) RED♪いい.かさばらないし,かっこいいし,ほんと快適♪

唯一かさばったケーブルは,こんなふうに編んでみたw




そういや,ケーブルの材質変わった?iPhone のときも思ったんだよな.新しいからかなぁ.iPod 5G のケーブルみたいに自然に垂れ下がらない.

参考文献:
iPod情報局: 三つ編みヘッドホンコードで絡まりを追放
テド★えにっき +とらちっく: 編み編みshuffleさん