C# 调用 C++ DLL 时 bool 返回值异常:Release 模式下 false 变 true
简介
在近期测试中,使用 C# 通过 P/Invoke 调用 C++ DLL 中的函数,返回值为 Bool 类型的数据存在一些致命异常。
当测试 return false 时,Debug 中运行正常,在 Release 中运行偶发接收到的值为 true。
偶发情况为使用 printf 打印一些文本与写入文件等一些理论上与返回结果毫无关联的事件,就会导致结果正确。
代码
1 | EXPORT_DLL bool Test(); |
1 | [] |
错误分析
字节分析
通常认为 bool 在 C++ 和 C# 中都是 true/false,应该完全一致,但实际上并不是。
C++ 在 MSVC 编译器中 bool 通常占 1 byte,表示:
1 | false = 0x00 |
C# P/Invoke bool 按照 Windows BOOL 处理,通常占 4 byte,表示:
1 | false = 0x00000000 |
为什么 Debug 正常,Release 异常
Debug 模式:优化关闭、栈初始化、寄存器状态更稳定
Release 模式:开启优化、寄存器复用、删除无用代码
为什么增加打印或日志后问题消失
加入了一些代码后,可能改变了:栈布局、寄存器使用、编译器优化结果;导致了 Release 下返回寄存器状态发生变化产生的碰巧修复。
解决方案
修改 C# Bool 返回值大小
此为最小修改,UnmanagedType.I1 表示按照 1 byte 读取返回值,对应 C++ 的 bool。
1 | [] |
DLL 接口不要使用 bool,改用 int
bool 是编程语言类型,不同平台、不同语言对于 bool 的 ABI 定义可能不同。
对于跨语言的 DLL 调用,更推荐使用 int 代替 bool。
1 | EXPORT_DLL int Test(); |
1 | [] |