P/Invoke を使用して C# から C 関数を呼び出すと、呼び出し規約が一致しない場合にクラッシュが発生する可能性があります。 この記事では、これらの対立の背後にある理由を探ります。
呼び出し規約の不一致とその影響
一般的なシナリオには、__stdcall
規則を使用する C 関数が含まれますが、対応する C# DllImport
属性は CallingConvention.Cdecl
を指定します。これは次の理由で発生します:
__stdcall
: Windows API および多くの C 関数の標準呼び出し規則。呼び出された関数 (callee
) はスタックをクリーンアップする役割を果たします。 これは P/Invoke のデフォルトです。__cdecl
: C コードで使用されます。呼び出し関数 (caller
) はスタックのクリーンアップを担当します。問題: スタックの不均衡
スタックのクリーンアップに関して呼び出し元と呼び出し先の意見が一致しない場合、スタックの不均衡が生じます。これにより、スタック情報が失われるため、クラッシュ、予期しない動作、および信頼性の低いデバッグが発生します。
その他の呼び出し規約 (およびそれらが重要な理由)
__thiscall
: C でメンバー関数として使用されます。 継承の複雑さとコンパイラの違いのため、.NET P/Invoke では直接サポートされていません。__fastcall
: 引数の受け渡しに CPU レジスタを使用します。 マネージ コードではサポートされていません。__clrcall
: __stdcall
、__cdecl
、__fastcall
の側面と実行時の安全性チェックを組み合わせたマネージド コード規約。デフォルトの P/Invoke 規約が問題を引き起こす理由
デフォルトの P/Invoke 呼び出し規約 (stdcall
) は、__cdecl
を使用してコンパイルされた C コードと衝突することがよくあります。これは、__stdcall
と Windows API の歴史的な関連付けに由来し、すべての C 関数がそれを使用するという (誤った) 仮定につながります。 この不一致により、前述のスタック クリーンアップの問題が発生します。
以上が`__stdcall` c関数とインターフェースするときに「cdecl」を使用してc#p/呼び出しが時々クラッシュするのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。