1. ホーム
  2. c++

[解決済み] Windowsで__cdeclと__stdcallのどちらを使うか?

2023-04-11 10:56:58

質問

私は現在 Windows 用の C++ ライブラリを開発しており、DLL として配布される予定です。より正確には、私の DLL 内の関数は、DLL を再コンパイルすることなく、MSVC++ および MinGW の複数のバージョンでコンパイルされたコードから使用可能である必要があります。しかし、どの呼び出し規則が最適なのか混乱しています。 cdecl それとも stdcall .

時々、quot; the C calling convention is the only one guaranteed to be same accross compilers" というような発言を耳にしますが、これは " のような発言とは対照的です。 の解釈にはいくつかのバリエーションがあります。 cdecl の解釈にはいくつかのバリエーションがあり、特に値を返す方法には "を返す方法についてです。これは、特定のライブラリ開発者(たとえば libsndfile のような) 特定のライブラリ開発者が、配布する DLL で C の呼び出し規約を使用することを、目に見える問題なしに止めることはできないようです。

一方 stdcall の呼び出し規約はよく定義されているようです。私が聞いたところでは、すべての Windows コンパイラは、Win32 と COM で使用される規約であるため、基本的にこれに従うことが要求されるようです。これは、Win32/COMをサポートしないWindowsコンパイラは、あまり有用ではないという前提に基づいています。フォーラムに投稿された多くのコード・スニペットは、関数を次のように宣言しています。 stdcall と宣言していますが、私は なぜ .

あまりにも多くの矛盾した情報があり、検索するたびに異なる答えが返ってくるので、2 つのうちどちらかを決めるのにあまり役に立ちません。私は、なぜどちらかを選ぶべきなのか (または、なぜ 2 つが同等なのか) について、明確で詳細な、論拠のある説明を探しているのです。

この質問は、quot;classic" 関数に適用されるだけでなく、仮想メンバー関数呼び出しにも適用されることに注意してください。 ここで そこ ).

どのように解決するのですか?

私はちょうどいくつかの実際のテスト (MSVC++ と MinGW で DLL とアプリケーションをコンパイルし、それらを混ぜる) を行いました。見たところ、私はより良い結果を得るために cdecl の呼び出し規約の方が良い結果でした。

より具体的には:問題点は stdcall を使用した場合でも、MSVC++ が DLL エクスポート テーブルの名前を混乱させることです。 extern "C" . 例えば foo_foo@4 . この現象は __declspec(dllexport) を使用したときだけで、DEF ファイルを使用したときには起こりません。しかし、DEF ファイルはメンテナンスの手間がかかると私は考えており、使用したくありません。

MSVC++ の名前のマングリングは、2 つの問題を引き起こします。

  • 使用方法 GetProcAddress を使用すると、DLLは少し複雑になります。
  • MinGWはデフォルトで、装飾された名前の前にアンデスコアを付けません (例えば、MinGWは、装飾された名前の前に foo@4 の代わりに _foo@4 の代わりに ) を使用すると、リンクが複雑になります。また、アンダースコアのバージョンと互換性のない DLL やアプリケーションが出回る危険性もあります。

私は cdecl 規約を試してみました。MSVC++ と MinGW の間の相互運用性は完璧に、すぐに機能し、名前は DLL エクスポート テーブルで装飾されないままです。仮想メソッドでさえも機能します。

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