88

私は現在、DLL として配布される Windows 用の C++ ライブラリを開発しています。私の目標は、バイナリの相互運用性を最大化することです。より正確には、DLL の関数は、DLL を再コンパイルすることなく、MSVC++ と MinGW の複数のバージョンでコンパイルされたコードから使用できる必要があります。ただし、どの呼び出し規約が最適か、cdeclまたはstdcall.

「C の呼び出し規則は、コンパイラ間で同じであることが保証されている唯一の規則です」などのステートメントを時々耳にcdeclます。これは、特定のライブラリ開発者 ( libsndfileなど) が配布する DLL で C 呼び出し規則を使用することを止めるようには見えませんが、目に見える問題はありません。

一方、stdcall呼び出し規約は明確に定義されているようです。私が聞いたところによると、これは Win32 と COM で使用される規則であるため、すべての Windows コンパイラは基本的にそれに従う必要があります。これは、Win32/COM をサポートしない Windows コンパイラはあまり役に立たないという前提に基づいています。フォーラムに投稿された多くのコード スニペットは関数を として宣言していますが、その理由stdcallを明確に説明している 1 つの投稿が見つからないようです。

矛盾する情報が多すぎて、検索を実行するたびに異なる答えが得られます。どちらか一方を選択する必要がある理由 (または 2 つが同等である理由) について、明確で詳細な議論のある説明を探しています。

この質問は、「クラシック」関数だけでなく、仮想メンバー関数呼び出しにも適用されることに注意してください。ほとんどのクライアント コードは、純粋な仮想クラスの「インターフェイス」を介して DLL とやり取りするためです (たとえば、 hereおよびthere で説明されているパターンに従います)。

4

3 に答える 3

81

実際のテストをいくつか行いました (MSVC++ と MinGW を使用して DLL とアプリケーションをコンパイルし、それらを混合します)。cdeclどうやら、呼び出し規約の方が良い結果が得られました。

より具体的にstdcallは、 の問題は、extern "C". 例えばfoo​​になり_foo@4ます。これは を使用している場合にのみ発生__declspec(dllexport)し、DEF ファイルを使用している場合には発生しません。ただし、私の意見では、DEF ファイルはメンテナンスが面倒であり、使用したくありません。

MSVC++ の名前マングリングには、次の 2 つの問題があります。

  • DLL での使用GetProcAddressは少し複雑になります。
  • デフォルトでは、MinGW は装飾された名前の先頭にアンデススコアを追加しません (たとえば、MinGW はfoo@4の代わりに使用します_foo@4)。これにより、リンクが複雑になります。また、「アンダースコア バージョン」と互換性のない DLL およびアプリケーションの「非アンダースコア バージョン」が実際にポップアップ表示されるリスクもあります。

MSVC cdecl++ と MinGW の間の相互運用性は、すぐに使える状態で完全に機能し、名前は DLL エクスポート テーブルで装飾されていません。仮想メソッドでも機能します。

これらの理由から、cdecl私にとって明らかな勝者です。

于 2011-07-09T13:37:25.403 に答える
20

2 つの呼び出し規則の最大の違いは、" _ _cdecl" は呼び出し元で関数呼び出しの後にスタックのバランスを取る負担を課すことです。これにより、可変量の引数を持つ関数が可能になります。「__stdcall」規約は本質的に「単純」ですが、この点では柔軟性が低くなります。

また、マネージ言語はデフォルトで stdcall 規則を使用していると思います。そのため、cdecl を使用する場合、P/Invoke を使用する人は呼び出し規則を明示的に指定する必要があります。

したがって、すべての関数シグネチャが静的に定義される場合、cdecl ではないにしても、おそらく stdcall に傾倒します。

于 2011-06-28T18:19:26.713 に答える