• 締切済み

関数のポインタ

現在マルチスレッドアプリケーションを作成しています。 ところが、 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

  • マルチメディアタイマー

    初めて質問させていただきます。 Visual C++ 6.0でMFCのダイアログベースでマルチメディアタイマーを使おうとしてるのですが、 class CTimeCounter { public: LPTIMECALLBACK lpTimeCallback; UINT TimerID; UINT uPeriod; UINT uDelay; void GetPeriod(); void AttachAD(LPTIMECALLBACK lpProc); CTimeCounter(); virtual ~CTimeCounter(); }; void CTimeCounter::AttachAD(LPTIMECALLBACK lpProc) { TimerID = uPeriod = NULL; GetPeriod(); //最小分解能を取得し、uPeriodに代入 this->uDelay = uPeriod; this->lpTimeCallback = lpProc; } としてCTimeCounter ctcを宣言したのですが、OnInitDialogのTODOの箇所でコールバック関数のアドレスを取得しようとして ctc.AttachAD(this->TimerProc); とすると error C2664: 'AttachAD' : 1 番目の引数を 'void (unsigned int,unsigned int,unsigned long,unsigned long,unsigned long)' から 'void (__stdcall *)(unsigned int,unsigned int,unsign ed long,unsigned long,unsigned long)' に変換できません。 というエラーを返されます。これはどう対処すればいいのでしょうか? よろしくお願いします。

  • SDKでのエラーなのですが。

    はじめまして。 SDKの勉強で猫でもわかる~のHPの第37章のサンプルを実行したのですが、 --------------------構成: 037 - Win32 Debug-------------------- コンパイル中... main.cpp D:\SDK\037\main.cpp(230) : error C2664: 'CallWindowProcA' : 1 番目の引数を 'int (__stdcall *)(void)' から 'long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)' に変換できません。 (新しい機能 ; ヘルプを参照) この変換には reinterpret_cast, C スタイル キャストまたは関数スタイルのキャストが必要です。 D:\SDK\037\main.cpp(248) : error C2664: 'CallWindowProcA' : 1 番目の引数を 'int (__stdcall *)(void)' から 'long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)' に変換できません。 (新しい機能 ; ヘルプを参照) この変換には reinterpret_cast, C スタイル キャストまたは関数スタイルのキャストが必要です。 cl.exe の実行エラー 037.exe - エラー 2、警告 0 というようなエラーが出てしまいました。 このエラーを回避するにはどのようにすればいいのでしょうか?

  • CreateThreadのエラー

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問> 何も実行しないスレッドを作成するようにコーディングしたのですが、 「error C2440: 'type cast' : '' から 'unsigned long (__stdcall *)(void *)' に変換することはできません。」 というエラーが出ました。 これは、何が原因で、解決方法はありますか? <ソース> void CMyDlg::OnButton1() { HANDLE handle; DWORD id; handle = CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&id); } void CMyDlg::ThreadFunc(void) { } <ヘッダ> void ThreadFunc(void); 宜しければご指摘お願い致します。

  • メンバ関数(メソッド)をマルチスレッドにしたい

    環境はWinXPでVisual Studio 2005を使用しています。 C言語で関数をマルチスレッド化するにはこんな感じでOKでした。 // マルチスレッド関数 void Thread( void * ) { } void MainFunc() {   (HANDLE)_beginthread( Thread, 0, NULL ); } こんな風にスレッド関数をC++のメソッドに変えてうまくいくかと思い class Test_c { public:   void Thread( void * ); } ; // マルチスレッド関数 void Test_c::Thread( void * ) { } void MainFunc() {   Test_c t t;   (HANDLE)_beginthread( t.Thread, 0, NULL ); } とするとエラーが出てきてしまい、コンパイルが通りませんでした。 C++のメンバ関数をマルチスレッド関数としたい場合はどの様に書けばよいのでしょうか・・?

  • コールバック関数指定時のエラー

     EnumWindows( EnumWndProc,(LPARAM) NULL); この記述の行で下記のエラーが出ます。 宣言は  BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam); としてあります。 error C2664: 'EnumWindows' : 1 番目の引数を 'int (struct HWND__ *,long)' から 'int (__stdcall *)(struct HWND__ *,long)' に変換できません。 (新しい機能 ; ヘルプを参照) スコープ内でこの名前を持つ関数でターゲット型に一致するものはありません。 キャストすればよいのかと思い下行のようにしました。  EnumWindows((__stdcall *) EnumWndProc,(LPARAM) this); そうすると次のエラーになります。 error C2059: 構文エラー : '__stdcall' このエラーを回避するにはどうしたらよろしいのでしょうか。 皆様ののお知恵を拝借させてください。 よろしくお願いいたします。

  • 配列ポインタの関数中のメモリ領域

    C初心者です。 関数中で配列ポインタを宣言する場合についての質問です。 たとえばDouble型の2次元のローカルな配列ポインタを用いる場合、 その配列要素数が100である場合は void 関数名(引数1,引数2,...){ int i; double *a[2]; for(i=0;i<2;i++){ a[i] = (double*)malloc(100*sizeof(double)); } for(i=0;i<2;i++){ free(a[i]); } } またこの値を引数1とする場合、引数1をoutとすると void 関数名(double *out,....) とし、 for(i=0;i<2;i++){ out[i] = a[i]; } とすればよいのでしょうか? もしこれがあっているとすると、つぎのような現象で困っています。 配列要素数を50000個ぐらいとし、複数の関数で、同様に mallocを用いて、配列ポインタのローカルでメモリ領域を確保しようとした場合、コンパイルは成功するのですが、その後実行すると、エラーが発生したというメッセージとともにコマンドウィンドが強制終了します。 コンパイラはVisual C++ EXpress Edition 2008です。 データサイズを小さくすると、エラーは起きません。 malloc関数で確保するメモリサイズは、関数の入力引数で定義された変数を用いて計算しており、データサイズに応じて変更されます。 よろしくお願いいたします。

  • (マルチスレッド)_beginthreadexに複数の引数を渡す

    現在プログラムでマルチスレッドをやろうとしているのですが、 マルチスレッドの関数に数値や配列などの引数を渡すことは可能でしょうか? MSDNで調べてみると、_beginthreadex関数の4番目のNULLのところに引数リストを 指定できるとあったのですが、その意味が良くわかりませんでした。 以下のプログラムの場合にマルチスレッドに変数a, b, cを引数として渡したい場合は どのように書けばいいのでしょうか? #include <stdio.h> #include <windows.h> #include <process.h> unsigned WINAPI MyThread( void *lpx ){ while (1) { printf("スレッド実行中\n"); Sleep(1000); } return 0; } void main(){ // スレッドに渡したい変数の宣言 int a = 128; int b = 256; int c = 512; // スレッドIDの宣言 DWORD thID; // マルチスレッドの開始 (HANDLE)_beginthreadex( NULL, 0, &MyThread, NULL, 0, (unsigned int*)&thID ); // ループ while (1) { printf("メイン関数実行中\n"); Sleep(2000); } }

  • 関数内に関数は無理でしょうか? 子スレッド

    CやC++についてまだよくわかっていないのですが、関数内に関数を書くと 「コンパイラ エラー C2601 ローカル関数の定義が正しくありません。」となります。 そこで以下の子スレッドのように関数を関数外に定義して、利用する変数も関数外に定義しました。 変数を外部に定義すると、メモリアクセスになるので、できるだけ避けたかったために 関数内に子スレッドを最初書いていたのですが、何か良い方法はありますか? 子スレッドの引数や戻り値を利用できればいいのですが、そんなことできるのかもわかりません。 あと、関数を配列のように定義できるのでしょうか? test_thread_0, test_thread_1と逐一書くのが面倒です。 int sum1 = 0, sum2 = 0; unsigned __stdcall test_thread_0(void *lpx) // lpxはおまじない? { // 全て足す for (int i = ST1; i <= EN1; i++){ sum1 += Data1[i] * Data2[i]; } return 0; // 正常という意味? } unsigned __stdcall test_thread_1(void *lpx) { // 全て引く for (int i = ST2; i <= EN2; i++){ sum2 -= Data1[i] * Data2[i]; } return 0; }

  • プロジェクトを作った際のエラー

    VisualC++ 2005 Express Editionを使用してます win32コンソールアプリケーション - アプリケーション設定 - windowsアプリケーション この新しく作ったプロジェクトを何もいじらずにビルドすると __imp__EndPaint@8 が関数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) で参照されました。 test.obj : error LNK2019: 未解決の外部シンボル __imp__BeginPaint@8 が関数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) で参照されました。 test.obj : error LNK2019: 未解決の外部シンボル __imp__DefWindowProcW@16 が関数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) で参照されました。 test.obj : error LNK2019: 未解決の外部シンボル __imp__DestroyWindow@4 が関数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) で参照されました。 test.obj : error LNK2019: 未解決の外部シンボル __imp__DialogBoxParamW@20 が関数 "long __stdcall WndProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WndProc@@YGJPAUHWND__@@IIJ@Z) で参照されました。 test.obj : error LNK2019: 未解決の外部シンボル __imp__EndDialog@8 が関数 "int __stdcall About(struct HWND__ *,unsigned int,unsigned int,long)" (?About@@YGHPAUHWND__@@IIJ@Z) で参照されました。 C:\C++test\test\Debug\test.exe : fatal error LNK1120: 外部参照 19 が未解決です。 というエラーが出てしまいます 800文字オーバーしてしまうのでエラーの前半部分を消してあります この原因と解決方法を教えてください よろしくお願いします

  • C言語のvoid型ポインタ変数について。

    C言語のvoid型ポインタ変数について。 C言語のvoid型ポインタ変数について質問があります。 組み込み系の開発を行っているのですが、現在使用しているシステムで、 提供されている "API" を介してアプリケーション部のソフト作成を行っています。 この "API" ですが、引数の多くはvoid型ポインタとなっています。 ある人がこの引数がvoid型となっているのを見て、 『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』 とおっしゃいました。 この意味がよくわからなかったのですが、なぜ void型はよろしくないんでしょうか? -- 僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる 汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。 -API例---- int _exApiKannsuu( char in_data, void* out_data ) "in_data" をもとに "out_data" を取得する。 どーやらこの "out_data" が void型 であるのががよくないらしい・・

専門家に質問してみよう