__stdcallとは何ですか?


151

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

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

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

#define WINAPI      __stdcall

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


2
@AndrewProckこの場合、「ダミー」の変更は問題ありませんでしたが、一般的には、 sを使用して、愚かな(そして逆効果の適切なケース)6文字以上を回避できます。
Adi Inbar 2014年

回答:


170

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

他の呼び出し規約の数がありますが、__cdecl__thiscall__fastcallそして素晴らしく命名__declspec(naked)__stdcallWin32システムコールの標準の呼び出し規約です。

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

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


8
非常にstarngeクラッシュの例については、この質問を参照してくださいstackoverflow.com/questions/696306/...
sharptooth

私が間違っていなければ、これらの呼び出し規約はコンパイラがアセンブリコードを生成する方法を制御します。アセンブリコードとインターフェイスする場合、スタックの問題を防ぐために呼び出し規約に注意することが重要です。いくつかの規則を文書化した素敵な表があります:msdn.microsoft.com/en-us/library/984x0h58.aspx
Nicholas Miller

これにより、特定の不正な最適化が無効になると言えますか?
Kesari

40

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

ウィキペディアの記事は、そこに見られる異なる呼び出し規約の概要を説明します。


18

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


12

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


3
また、standard-cであるため、_standard_callと混同しないでください。これが__stdcallのポイントだと思う人もいるかもしれません
ヨハネスシャウブ-litb 08年

3
小さなnitpick:__stdcallの代わりに__cdeclを使用するいくつかのWindows APIがあります-通常、wsprintf()などの可変数のパラメーターを取るものです。
マイケルバー

あなたが正しい。CRT関数のように見える名前が付けられていますが、これはAPIです。たまたま、C#からP / Invokeする方法を知っていますか?
Windowsプログラマー、

私はこれをテストしていませんが、pinvoke.netは次のシグネチャを提供します:「static extern int wsprintf([Out] StringBuilder lpOut、string lpFmt、...);」
マイケル・バー、

私の直感では、C#コンパイラは__cdecl規則を使用することを知らないでしょう。
Windowsプログラマー



4

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

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

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

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


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));
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.