※ これはC言語の話です。
私はvoid *
型関連のキャスト恐怖症で、void *
なキャストを見ると恐怖で目がうるんでしまいます。
なんとかvoid *
なキャストを明示的に書かないで済ませられないのでしょうか?
代入&引数渡し
void *
型の変数に値を代入する場合、代入元がポインタ型であれば明示的なキャストは不要です。
なので…
int value;
void *pVoid = (void *)&value;
あああ、キャスト恐い!!
しかも不要なのに意味ありげな()
で可読性が暴落ですよ(?)
大体1行に2回もvoid *
って書かされてるのはDRYじゃない。
キャストは取っ払っちゃって、
int value;
void *pVoid = &value;
でいい。
タイプ数と横幅を節約できて幸せ!
プログラマの意図も、こっちの方が明確に過不足なく伝わります。
なので関数にパラメータを渡す場合も、
// void *を要求する関数
int requireVoidPointer( void *pVoid );
// 呼び出し
// (void *)&valueにする必要なし
int value;
requireVoidPointer( &value );
これでよし。
よかった、キャスト見ずに済みました…
コールバック関数のパラメータ
コールバック関数を受け取る関数は、以下のパラメータを持たせるパターンが多いですよね。
- コールバックの関数ポインタ
- コールバックを呼び出す際に渡す
void *
型の変数
こうすることによって、コールバックを受け取る関数をより汎用的に使えます。
// コールバック受け取る関数
int requireCallBack( void (* pCallBack)(void *pVoid), void *pParam )
{
pCallBack( pParam );
}
こういった関数を使用する場合、コールバックとして渡される関数のパラメータはvoid *
型である必要はありません!(ポインタ型であればよい)
なので、以下のようなコードを見ると辛い。
// コールバック受け取る関数
int requireCallBack( void (* pCallBack)(void *pVoid), void *pParam );
void main( void )
{
int value = 10;
// コールバック受け取る関数呼び出し
requireCallBack( addThreeCBR, &value );
}
// コールバック用の関数
void addThreeCBR( void *pVoid )
{
// わぁ、なんか変なキャスト
int *pValue = (int *)pVoid;
*pValue += 3;
}
ああ、なんでこんな目に…
どこかで設計ミスったの?
このaddThreeCBR()
は、パラメータとしてint *
型の変数を受け取らないとちゃんと動作しません。
それなのに関数の型が、requireCallBack()
のプロトタイプに引きずられてint addThreeCBR( void *pVoid )
になってしまっています。だから関数の内部で無駄なキャストが必要になってしまう。
実は、requireCallBack()
に渡すコールバック関数の型がvoid (* pCallBack)(void *pVoid)
だからって、本当に渡すコールバック関数のパラメータをvoid *
にする必要はありません。代入の時と同じで、ポインタ型でさえあればいいんです。
もう思い切って、addThreeCBR()
のパラメータをint *
型にしちゃいましょう!
// パラメータをvoid *ではなくint *に変更
void addThreeCBR( int *pValue )
{
*pValue += 3;
}
ああ、まがまがしいキャストと無駄なローカル変数が消せてすっきり!