如果调用约定不匹配,使用 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 函数都使用它的(错误的)假设。 这种不匹配会导致上述堆栈清理问题。
以上是为什么使用'Cdecl”的 C# P/Invoke 调用在与'__stdcall” C 函数交互时有时会崩溃?的详细内容。更多信息请关注PHP中文网其他相关文章!