165

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

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

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

#define WINAPI      __stdcall

これは何をしますか?これがリターンタイプの後に何かを持っていることに私は混乱しています。何__stdcallのために?戻り型と関数名の間に何かがあるとはどういう意味ですか?

4

8 に答える 8

195

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

他にも多くの呼び出し規約__cdecl、、、および素晴らしい名前のがあり__thiscallます。 Win32システムコールの標準の呼び出し規約です。__fastcall__declspec(naked)__stdcall

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

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

于 2008-11-18T02:18:06.080 に答える
44

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

ウィキペディアの記事には、そこにあるさまざまな呼び出し規約の概要が記載されています。

于 2008-11-18T02:20:26.760 に答える
23

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

于 2008-11-18T02:24:57.313 に答える
12

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

于 2008-11-18T02:31:24.900 に答える
10

見て:

http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

于 2009-06-30T15:02:01.800 に答える
5

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

ドキュメントは次のとおりですが、最初の部分を理解していない限り、あまり意味がありません:http:
//msdn.microsoft.com/en-us/library/zxk0tw93.aspx

于 2008-11-18T02:19:05.593 に答える
5

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

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

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

ここで、fnnameには、スタックに直接プッシュする引数があります。

于 2009-04-17T04:03:38.473 に答える
1

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

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

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

ExecuteCommand 関数、beginthreadex がそれを呼び出すために、メソッド シグネチャで __stdcall キーワードを使用する必要があります。

unsigned int __stdcall Scene::ExecuteCommand(void* command)
{
    return system(static_cast<char*>(command));
}
于 2016-05-23T03:13:35.253 に答える