【问题标题】:How are runtime errors handled in a C library compiled in C++?在 C++ 中编译的 C 库中如何处理运行时错误?
【发布时间】:2011-12-13 00:22:15
【问题描述】:

假设我有一个 C 库,我正在使用 Visual Studio 链接到 Windows 上的 C++ 程序。这个 C 库是黑盒子。如果此库中发生致命错误(例如取消引用 null),程序/OS 将如何处理此运行时错误?我知道在 C++ 中存在空引用异常,因此您可能可以使用 try/catch 处理此类错误,但由于这是一个 C 库,它不会发出 throw,对吧?那么会发生什么呢?程序将终止,但如果不是 C++ 异常,是通过什么方式终止的?

【问题讨论】:

  • C++ 中的空引用异常?这不是标准要求的,是吗?我很确定我使用的 C++ 实现都只是段错误。
  • 也许巧妙地使用 atexit() 会有所帮助?不过不确定。
  • 也许我理解错了,但我认为 MSVC 发出了取消引用空指针的异常。他们称其为“空引用异常”,也许这里的意思不是 C++ 异常?此外,当我启用调试异常(Visual Studio 中的调试菜单 >> 异常...)时,当发生这样的空指针取消引用时,我会中断。
  • NullReferenceException 是一个 .NET 类。你在考虑 C++/CLI 吗?这不是标准的 C++。
  • 据我所知,这不是 C++ 异常。它更像是一个信号。

标签: c++ c windows exception


【解决方案1】:

您永远不能“处理”取消引用空指针。一旦你这样做了,你的程序就不再处于定义明确的状态,并且没有办法确定地继续下去。唯一的做法是terminate(),如果您尚未注册 SIGSEGV 处理程序,操作系统将代表您执行此操作。

“错误”一词有几个含义,可能会令人困惑:一方面,无法执行其预期任务的函数可以说遇到了“错误”,它应该发出信号这可以通过一个合适的返回值,或者通过抛出一个异常。这种行为最好称为失败。必须准备一个正确的程序来处理函数可能返回的所有可能方式。另一方面,编程错误只会导致错误甚至是格式错误的程序。一个正确的程序绝不能有任何编程错误。

例如,malloc() 可能失败(如果它找不到足够的空间),它通过返回一个空指针来发出信号,但是如果它取消引用 @ 的结果,你的程序就会出错987654323@不检查。

您永远无法通过进一步的编程“捕捉”或“处理”编程错误。相反,一个正确的程序必须正确预测和处理组件函数的所有失败条件,并且递归地正确编写的函数必须始终以定义良好的方式返回并适当地发出失败信号。

【讨论】:

  • 但是根据我的一般调试,取消引用 NULL 指针会导致异常。那么,有了catch(...),你就不能处理了吗?
  • @RobertDailey:不。例外是故意的,正确编程的一部分。取消引用空指针永远不会正确。我将在帖子中添加另一段,敬请期待。
  • @RobertDailey:不要将 C++ 异常与 CPU 异常混淆。它们是完全不同的两件事。
  • 非常好的答案Kerrek。我熟悉有关异常或您所说的“失败”的一般原则和设计。这是我不熟悉的“CPU异常”。如何处理编程错误的实现实际上是这里的问题。虽然您的答案包含一些非常好的信息,但它并没有完全回答我的主要问题。我仍然赞成:)
【解决方案2】:

在本机代码中取消引用空指针将导致 Windows 上的“访问冲突”或 Unix/Linux 上的“分段错误”。同一事物的不同名称。是 CPU 检测到错误,并调用操作系统中的处理程序,该处理程序终止进程。

在基于 VM 的语言(例如 .NET 或 Java)中取消引用空引用将引发您可以捕获的异常。这是可能的,因为 VM 位于程序和 CPU 之间,它可以在尝试实际上取消引用之前检测到 null。

C 库是本机代码,因此您会遇到访问冲突。你会从一个真正的 C++ 程序中得到相同的结果,它也被编译为本机代码。但是,如果您使用的是托管 C++ 或 C++/CLI,它们是编译为 CIL 并在 .NET 运行时上运行的变体,因此在这种情况下您会收到 NullReferenceException。

【讨论】:

  • “无效页面错误”可以追溯到上个世纪。这是 Windows NT 分支中的“访问冲突”。
  • @HansPassant,哎呀。 :-) 我实际上并不经常使用 Windows,并且在极少数情况下发生崩溃时,我只会看到“遇到问题并需要关闭”对话框,所以我没有注意到该术语已更改。固定。
  • 这太棒了,正是我所需要的!这解释了实现如何处理此类错误(如取消引用空指针)的详细信息,这是我在 OP 中所问的。
【解决方案3】:

支持使用 C++ 捕获的“异步”或“结构化”异常(例如无效的内存访问)catch 关键字是 C++ 语言的 MSVC 扩展。

只要使用正确的编译器选项/EHahttp://msdn.microsoft.com/en-us/library/1deeycx5%28v=VS.100%29.aspx,即使它们源自 C 函数,您也可以捕获此类异常

您还可以选择使用 Microsoft 的“结构化异常”处理语言扩展(在 C 中也可用),它使用 __try__except 关键字:http://msdn.microsoft.com/en-us/library/swezty51.aspx

【讨论】:

  • 您说异常可以源自 C 函数,但如何? C 函数应该与不支持异常的 C 保持向后兼容。你能解释一下吗?
  • 异常源自 Windows 操作系统和运行时库。这不是一个 C++ 异常,就像迈克尔说的那样,它是一个“Windows 结构化异常”。这些被 __try 和 __except 块捕获,这是微软对 C 和 C++ 语言的扩展。进一步的 Microsoft 扩展允许 C++ 的 catch 也捕获那些结构化异常。
猜你喜欢
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 2020-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多