CDECLでは、引数が逆の順序でスタックにプッシュされ、呼び出し元がスタックをクリアして、結果がプロセッサレジストリ経由で返されます(後で「レジスタA」と呼びます)。STDCALLには1つの違いがあります。呼び出し元はスタックをクリアしません。呼び出し先はクリアします。
あなたはどちらがより速いかを求めています。誰も。可能な限り、ネイティブの呼び出し規約を使用する必要があります。特定の規則を使用する必要がある外部ライブラリを使用する場合に、方法がない場合にのみ規則を変更します。
さらに、コンパイラーがデフォルトの規則として選択する可能性のある他の規則があります。つまり、Visual C ++コンパイラーは、プロセッサー・レジスターをより広範囲に使用するため、理論的には速いFASTCALLを使用します。
通常、いくつかの外部ライブラリに渡されるコールバック関数に適切な呼び出し規約の署名を与える必要があります。つまりqsort
、CライブラリからのコールバックはCDECLでなければなりません(コンパイラーがデフォルトで他の規約を使用する場合、コールバックをCDECLとしてマークする必要があります)またはさまざまなWinAPIコールバックはSTDCALL(WinAPI全体がSTDCALLです)。
その他の通常のケースは、いくつかの外部関数へのポインターを格納している場合です。つまり、WinAPI関数へのポインターを作成するには、その型定義にSTDCALLのマークを付ける必要があります。
そして、以下はコンパイラがそれをどのように行うかを示す例です:
/* 1. calling function in C++ */
i = Function(x, y, z);
/* 2. function body in C++ */
int Function(int a, int b, int c) { return a + b + c; }
CDECL:
/* 1. calling CDECL 'Function' in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call (jump to function body, after function is finished it will jump back here, the address where to jump back is in registers)
move contents of register A to 'i' variable
pop all from the stack that we have pushed (copy of x, y and z)
/* 2. CDECL 'Function' body in pseudo-assembler */
/* Now copies of 'a', 'b' and 'c' variables are pushed onto the stack */
copy 'a' (from stack) to register A
copy 'b' (from stack) to register B
add A and B, store result in A
copy 'c' (from stack) to register B
add A and B, store result in A
jump back to caller code (a, b and c still on the stack, the result is in register A)
STDCALL:
/* 1. calling STDCALL in pseudo-assembler (similar to what the compiler outputs) */
push on the stack a copy of 'z', then a copy of 'y', then a copy of 'x'
call
move contents of register A to 'i' variable
/* 2. STDCALL 'Function' body in pseaudo-assembler */
pop 'a' from stack to register A
pop 'b' from stack to register B
add A and B, store result in A
pop 'c' from stack to register B
add A and B, store result in A
jump back to caller code (a, b and c are no more on the stack, result in register A)