理解 P/Invoke 中的 Cdecl/__stdcall 冲突
P/Invoke 连接 C# 和 C,依赖匹配的调用约定来确保正确的参数传递和堆栈管理。 当使用默认(通常是 __stdcall
)P/Invoke 约定从 C# 调用使用 cdecl
约定的 C 函数时,会出现一个常见问题。
问题的根源
不同的调用约定以不同的方式处理堆栈清理:
__stdcall
:广泛用于 Windows API 和 COM,被调用者(C 函数)负责清理堆栈。__cdecl
:默认的 C 调用约定,调用者(C# 代码)处理堆栈清理。__thiscall
:用于C成员函数;由于其复杂性,P/Invoke 不直接支持它。不匹配的后果
仅将 extern "C"
添加到 C 代码并在 C# CallingConvention.Cdecl
属性中指定 DllImport
并不能解决问题。 不同的清理职责会导致堆栈损坏,甚至可能导致崩溃或微妙的、难以调试的错误,即使没有立即发出调试器警告。 堆栈可能会被清理两次,从而导致不可预测的行为。
解决方案:一致的约定
关键是一致性。 修改 C 函数声明以显式使用 __cdecl
:将 extern "C" int __stdcall InvokedFunction(int);
替换为 extern "C" int __cdecl InvokedFunction(int);
。 然后,确保您的 C# DllImport
属性匹配:
<code class="language-csharp">[DllImport("CPlusPlus.dll", ExactSpelling = true, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]</code>
要点
仔细注意调用约定对于可靠的 P/Invoke 互操作性至关重要。 在 C 和 C# 之间使用一致的约定可以消除堆栈不平衡并提高代码的整体稳健性。
以上是为什么__STDCALL C和CDECL C#调用P/Invoke中的冲突,如何解决?的详细内容。更多信息请关注PHP中文网其他相关文章!