C

(void *)なキャストしたくない

More than 1 year has passed since last update.

※ これは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;
}

ああ、まがまがしいキャストと無駄なローカル変数が消せてすっきり!