• 締切済み

関数のポインタ

現在マルチスレッドアプリケーションを作成しています。 ところが、 CreateThread(NULL, 0, listenThread, this, 0, &m_listenThreadId); この行でエラーが出ます。 エラー内容は、 3番目の引数を'unsigned long (void *)' から 'unsigned long (__stdcall *)(void *)' に変換できません。 です。関数のポインタについてもまだよく理解していないので、このエラーの意味が良く分かりません。 どなたか、エラーの意味と解決方法を教えて頂けませんか? コンパイラはVisual C++6.0です。 どうぞ宜しくお願いします。

みんなの回答

  • alfeim
  • ベストアンサー率58% (114/195)
回答No.4

解決方法は他の方が示されているので、私はstdcallの事を説明します。 関数や他の言語のプロシージャ、サブルーチンなどは名前付け規約と呼び出し規約が規格上決まっています。 Visual C++ではデフォルトの規約は_cdeclであり、規約では引数を右から左に向かってスタックに積み、つんだスタックの破棄は呼び出し側で行います。 それに対して_stdcallでは呼び出し順序こそ同じですが、スタックの破棄は呼び出された側が処理する事になっています(よってykkw_2001さんの示された方法でやった場合、コンパイルは通るでしょうがスタックの整合性が保てない事になるため危険です)。 なぜこのような規約になっているかは私も不勉強のため知らないのですが、_cdecl規約の利点として可変個の引数の関数を作る事が出来る、という事です。 たとえば入門用によく使われるprintf()関数などは第一引数のchar*の内容を解析して引数の個数を調べ、その数から判断してスタックから引数を自分で取ってくるようになっています(当然積んだ個数<パラメータの数の場合、ヤバイ事になります(^^;)。 んじゃ、なぜ_stdcallがあるのか?というのはx86系CPU(互換含む)では RET n (nは即値、プログラムコード上で既に決まっている定数の事) という命令があり、関数から戻るときに同時にスタックに積まれた引数を始末する事が出来るためです。 _cdeclではRET命令で戻ってきた後に呼び出し側が破棄する(といってもスタックポインタの操作だけですが)ため、速度は微妙に_stdcallのほうが早くなります。 そのため頻繁に呼び出されるWin32APIは一つのAPIを除いてすべて_stdcallで宣言されています(問題の一つはwsprintf関数です。MSDNの解説を見てみてください)。 実際には上記の呼び出し規約だけではなく、名前付け規約の方もかかってくる場合があります(CとC++を併用する場合とか)。そのへんは参考URLかMSDNを参照してください。 Helpに載っている事なので釈迦に説法かもしれませんが・・・ CreateThread APIでは標準C関数の初期化処理について問題が発生するため引数に渡す関数とそこから呼ばれる関数に標準C関数が無い事を確認してください。でないとメモリリークが発生します。 標準C関数を使いたい場合は_beginthread(), _beginthreadex()関数、 またはMFCのCWinThreadクラスをお使いください。

参考URL:
http://www.microsoft.com/japan/developer/library/default.asp?URL=/japan/developer/library/vccore/_core_argument_passing_
  • osaosa42
  • ベストアンサー率60% (20/33)
回答No.3

MFCを使っていいのなら、 ------------------------------------- CWinThread *pThread = AfxBeginThread( listenThread, this); ------------------------------------- で、スレッド作成したほうが簡単ですよ。 (listenThreadは、自作関数)

noname#30727
noname#30727
回答No.2

CreateThreadの3番目のパラメータは、  DWORD WINAPI ThreadFunc(LPVOID t) {} これと同様の関数のアドレスを必要とします。 というエラーです。WINAPIを付けていないのが原因だと思います。 余談ですが、関数(へ)のポインタと言うと、 void (PointerToFunction*)(int, int); などの、関数のアドレスを入れる変数を意味します。変数そのものがポインタで、その値はアドレスです。

  • ykkw_2001
  • ベストアンサー率26% (267/1014)
回答No.1

CreateThread(NULL, 0, (unsigned long (__stdcall *)(void *))listenThread, this, 0, &m_listenThreadId); じゃだめ?

関連するQ&A