関数呼び出しの内部を理解する(2)

今回は、呼び出し規約について説明していきます。

呼び出し規約は関数の引数の引き渡し方、引数利用後の処理の仕方を制御します。
これが関数の装飾名にも影響を与えます。



例を挙げましょう。

関数の呼び出し元では第1引数はレジスタに記憶する、第2引数はスタックに積むというような約束事を作ります。
関数の呼び出し先では、第1引数はレジスタ、第2引数はスタックというように約束事を守るように引数を取得します。
このようなルールを作れば、違う言語における引数の引渡しが可能になります。

つまり、DLL関数が呼び出せない方は呼び出し元と呼び出し先で違う規約を使っている結果、装飾名が異なっている場合があります。
もう1つの原因は、次回に説明しますが、「extern "C"」キーワードを理解していない事です。

私が知っている呼び出し規約は以下の通りです。

  • cdecl(C規約)
  • thiscall(C++メンバ関数規約)
  • stdcall(Windows標準関数規約)
  • fastcall(高速関数規約)
  • clrcall(.NET Framework専用規約)

この規約を守ることにより、C++で作成したDLLをVBから呼び出せるわけです。
順番に説明していきます。

CやC++で規約を意識せずに関数を作ると「cdecl」か「thiscall」になります。

cdeclはCPUのレジスタの数が少ないころに作られた規約で、引数をスタックメインで処理するため一般に低速です。同時に最大の互換性と柔軟性をもっています。printfが可変引数を扱えるのも「cdecl」のおかげです。

thiscallはC++がthisでアクセスできる関数、つまり、クラスのメンバ関数に使われる規約です。

stdcallは、Windows APIで使われている規約です。x86系CPUに対して若干の最適化を施します。可変引数を使えない分、「cdecl」より高速です。Platform SDK内のマクロである「WINAPI」を書く人は、#defineの定義が「_stdcall」になっている事も確認してください。

fastcallは主に「PASCAL言語」で利用される規約です。なので、BorlandのVCLはfastcallです。引数を優先してレジスタに積むため一般的に高速になります。

clrcallは.NET Frameworkの標準である「CLI」に基づく呼び出し規約です。詳細は省略します。

「Visual C++」「Borland C++ Builder」では関数名に呼び出し規約を含める事ができます。「GCC」も可能なはずです。

Visual C++でのコード例は以下のとおり(__stdcallの代わりにWINAPIと書くのが普通です)。

int __stdcall Func() { return 1; }

最後に呼び出し規約の適切な選択方法をまとめます。

  • VB、VC、C#等すべてをサポートするのは「stdcall」
  • CとC++だけをサポートするのは「cdecl」
  • C++クラスは「thiscall」が自動で利用されるため、Cから呼び出せない
  • 自分の中で閉じる関数は速度を理由に「fastcall」を利用しても良い

次回はC++の装飾名をCの装飾名にするキーワード、「extern C」について説明します。

Leave a Reply

4 コメント - "関数呼び出しの内部を理解する(2)"

更新通知を受け取る »
avatar
並び替え:   新しい順 | 古い順 | 最も評価の多い
big
ゲスト

簡潔で有意義な文章でした。
感謝します。

konuma
ゲスト

コメント有り難う御座います。
忙しくて大分更新あいてますが、COMとかエンタープライズ開発系の記事でも書いてみようと画策中です。

akita
ゲスト

とても参考になりました。
わかりやすかったです。

akio
ゲスト

すごくわかりやすかったです。
ありがとうございました。

wpDiscuz