我有一大块非托管 C++ 代码,正在 C# 项目上重用。非托管 C++ 代码包装在托管 C++ 代码层内,该代码与 C# 代码进行交互。目前,非托管 C++ 代码使用assert(false) 来引发严重错误。由于assert()写入stderr并且我的项目是一个GUI程序,我认为断言打印输出不会显示。我正在考虑用 throw new exception(...) 替换assert(false),然后在 C# GUI 层捕获并显示异常。我的问题是:
1) 用Exception() 替换assert() 是个好主意吗?如果不是为什么?
2) 如果在非托管 C++ 代码中引发异常,它们是否会正确传播到托管 C++,然后传播到 C# 代码(堆栈跟踪完整且正确)?
谢谢
最佳答案
1) Is replacing assert() with exception() a good idea? if not why?
assert
是一个调试工具。它将在发布版本中评估为无操作,并且不打算用作错误处理工具。在 C++ 中实现基于异常的错误报告系统是很自然的事情。
2) If exceptions are thrown inside unmanaged C++ code, will they propagate properly to the managed C++ and then to C# code (with the stack trace intact and correct)?
native 代码中抛出的 C++ 异常将转换为 SEHException从非托管代码移动到托管代码时。 C++ 异常可以在 native 代码、C++/CLI 互操作层或托管代码中处理。 (人类可读)调用堆栈信息在 native 代码中不可用。
有关混合模式环境中异常处理的背景信息:
C++ 异常(在 Microsoft 的 C++ 编译器中实现)以及 CLR 中的异常都构建在 SEH 异常之上。 Structured Exception Handling是 Windows 中内置的一项服务,任何可以与 C 接口(interface)的环境都可以使用该服务。共享相同的基础使异常能够从托管代码无缝传播到非托管代码,反之亦然。
所有 SEH 异常都携带存储在 EXCEPTION_RECORD
中的相同信息。 。 ExceptionAddress
成员用作构造堆栈跟踪的入口点。托管程序集包含足够的元数据来构造人类可读的堆栈跟踪。另一方面, native 可执行镜像则不然。虽然可以生成堆栈跟踪(例如使用 StackWalk64
),但除非相应的调试信息 (.pdb) 可用,否则不会包含任何符号信息。
堆栈跟踪的替代方案:
虽然堆栈跟踪可能会给您一些引发异常的提示,但它不包含任何对调试有用的信息,例如参数和局部变量。另一种选择是编写一个小型转储。 MiniDumpWriteDump
是一个非常强大的工具,可以让您非常精细地控制应包含哪些数据。非常好的介绍可以在Effective Minidumps - Part 1找到和 Effective Minidumps - Part 2 。小型转储可以加载到调试器(例如 Visual Studio 或 WinDBG)中并进行分析。通过匹配的调试符号(您应该将其添加到任何版本的源代码控制系统中),您将获得一个非常有效的基础设施来分析问题。根据可用的小型转储信息,您将获得所有线程的调用堆栈、传递给函数的参数、局部变量的内容、加载和卸载的模块等。
关于c# - 异常从非托管代码传播到托管代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18724205/