OKWAVEのAI「あい」が美容・健康の悩みに最適な回答をご提案!
-PR-
締切り
済み

関数のポインタ

  • すぐに回答を!
  • 質問No.134496
  • 閲覧数405
  • ありがとう数4
  • 気になる数0
  • 回答数4
  • コメント数0

お礼率 33% (2/6)

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

回答 (全4件)

  • 回答No.1
レベル13

ベストアンサー率 26% (267/1014)

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

じゃだめ?
  • 回答No.2

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

というエラーです。WINAPIを付けていないのが原因だと思います。

余談ですが、関数(へ)のポインタと言うと、
void (PointerToFunction*)(int, int);
などの、関数のアドレスを入れる変数を意味します。変数そのものがポインタで、その値はアドレスです。
  • 回答No.3
レベル8

ベストアンサー率 60% (20/33)

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

ベストアンサー率 58% (114/195)

解決方法は他の方が示されているので、私はstdcallの事を説明します。 関数や他の言語のプロシージャ、サブルーチンなどは名前付け規約と呼び出し規約が規格上決まっています。 Visual C++ではデフォルトの規約は_cdeclであり、規約では引数を右から左に向かってスタックに積み、つんだスタックの破棄は呼び出し側で行います。 それに対して_stdcallでは呼び出し順序こそ同じですが、スタ ...続きを読む
解決方法は他の方が示されているので、私は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クラスをお使いください。
このQ&Aで解決しましたか?
関連するQ&A
-PR-
-PR-
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-
-PR-
-PR-

特集


いま みんなが気になるQ&A

関連するQ&A

-PR-

ピックアップ

-PR-
ページ先頭へ