web-dev-qa-db-ja.com

__stdcallとは何ですか?

Win32プログラミングについて学んでいますが、WinMainプロトタイプは次のようになります。

int WINAPI WinMain ( HINSTANCE instance, HINSTANCE prev_instance, PSTR cmd_line, int cmd_show )

このWINAPI識別子が何であるかについて私は混乱し、見つけました:

#define WINAPI      __stdcall

これは何をしますか?私はこれが戻り値型の後に何かを持っていることで混乱しています。 __stdcallとは何ですか?戻り値の型と関数名の間に何かがある場合、それはどういう意味ですか?

136

__stdcallは、関数に使用される呼び出し規約です。これは、スタックのセットアップ、引数のプッシュ、および戻り値の取得に適用されるルールをコンパイラーに伝えます。

__cdecl__thiscall__fastcall、および素晴らしい名前の__nakedなど、他にも多くの呼び出し規則があります。 __stdcallは、Win32システムコールの標準呼び出し規約です。

ウィキペディアは 詳細 をカバーしています。

主に、コードの外部の関数(OS APIなど)を呼び出している場合、またはOSが呼び出している場合(ここではWinMainの場合)に重要です。コンパイラが正しい呼び出し規約を知らない場合、スタックが正しく管理されないため、非常に奇妙なクラッシュが発生する可能性があります。

157
Rob Walker

CまたはC++自体は、これらの識別子を定義しません。これらはコンパイラの拡張機能であり、特定の呼び出し規約を表しています。これにより、引数の配置場所、順序、呼び出された関数が戻りアドレスを見つける場所などが決まります。たとえば、__ fastcallは、関数の引数がレジスタを介して渡されることを意味します。

Wikipedia Article は、そこにあるさまざまな呼び出し規約の概要を提供します。

これまでの回答で詳細を説明しましたが、アセンブリにドロップダウンするつもりがない場合は、呼び出し元と呼び出し先の両方が同じ呼び出し規約を使用する必要があることを知っている必要があります。そうしないとバグが発生します見つけるのは難しいです。

16
MovEaxEsp

私はこれまでのすべての答えが正しいことに同意しますが、ここに理由があります。 MicrosoftのCおよびC++コンパイラは、アプリケーションのCおよびC++関数内の関数呼び出しの(意図した)速度のためのさまざまな呼び出し規則を提供します。いずれの場合も、呼び出し元と呼び出し先は、使用する呼び出し規則について合意する必要があります。現在、Windows自体が関数(API)を提供しており、それらは既にコンパイルされているため、それらを呼び出すときは、それらに準拠する必要があります。 Windows APIへの呼び出し、およびWindows APIからのコールバックは、__ stdcall規則を使用する必要があります。

10
10
MojeSmece

これは、関数がどのように呼び出されるか、つまり基本的にスタックに置かれる順番と、クリーンアップの責任者に関係しています。

ここにドキュメントがありますが、最初の部分を理解しない限り、それほど意味はありません。
http://msdn.Microsoft.com/en-us/library/zxk0tw93.aspx

5
Joel Coehoorn

__stdcallは、関数引数をスタックに入れるために使用されます。関数の完了後、自動的にメモリの割り当てを解除します。これは固定引数に使用されます。

void __stdcall fnname ( int, int* )
{
    ...
}

int main()
{
    CreateThread ( NULL, 0, fnname, int, int*...... )
}

ここで、fnnameは、スタックに直接プッシュする引数を持っています。

4
Rajesh Manem

今日までこれを使用する必要はありませんでした。私のコードではマルチスレッドを使用しており、私が使用しているマルチスレッドAPIはWindows 1(_beginthreadex)であるためです。

スレッドを開始するには:

_beginthreadex(NULL, 0, ExecuteCommand, currCommand, 0, 0);

ExecuteCommand関数MUST beginthreadexが呼び出すには、メソッドシグネチャで__stdcallキーワードを使用します。

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
1
Katianie