型void *を引数にとる関数の使い方
C言語のmemsetやmemcpyは自前でforループなどをつかって同じことをやるよりも高速だと言われている。そのためか,会社でもこれらの関数が使われるプログラムを見る機会は多い。ただし,けっこう微妙な感じで。例えば,以下のような感じ。
#define LENGTH_INT 4 void hoge() { int data[100]; memset((void *) data, 0, 100 * LENGTH_INT); /* なんかテキトーな処理 */ }
「なぜsizeofを使わない?」,「void *にキャストする必要あるか?」と配属当初は思っていたのだが,郷に入っては郷に従えを地でいく私はそのまま放置。さすがに自分で書くときはsizeofを使っていたし,他の人にmemsetの使い方を教えるときもsizeofを使うように言ってはいたが。
型void *へのキャストについては,意味はないけど問題はないだろうということで放置していた。それどころか,自分で書くときもキャストしてた。というのも,今までのとは違うやり方で書くと色々とめんどくさいのだ。
で,ここ最近のことだが,次のようなプログラムがあった。
void foo() { int data; memset((void *) data, 0, 100 * LENGTH_INT); /* なんかテキトーな処理 変数dataはintとして使われている*/ }
もちろんまともに動かないかというと,そうでもなくdataが未初期化のため場合によっては正しく動いているように見えることもあった。このプログラムはgcc(4.0.1)では警告がでることもなく普通にコンパイルできる(もしかしたらだす方法があるかもしれないが,-Wallではでなかった)。C言語的にはまったく問題ないし,ねらってこういうことを書くこともあるだろうし,それができるのがC言語の利点なわけだから当然か。
この例のような誤りを防ぐには,型void *へのキャストをせずにmemsetを呼び出すようにすれば良い。そうすれば型エラーになるので,gccは警告を出してくれる。Haskellを使ってる身としてはエラーではなく警告なのかと思ってしまうところだが。
他に良い方法を知っている人がいたら教えてください。