MinGW SEH和MinGW SJLJ有什么区别?

52

34
对于那些投票要关闭这个问题的人来说,这对于一个新程序员来说是完全可以理解的。MinGW的两个版本之间的差异完全基于新用户不理解的概念。 - nategoose
2个回答

54

SJLJ和SEH是两个不同的异常处理系统。

关于具体差异,您已经看到的资源已经涵盖了所有内容。

然而,关于安装哪一个更好,请选择SJLJ,除非您知道需要使用SEH。

2019更新:在现代系统上,没有理由使用SJLJ,因此上述建议应该反转。现在SEH更常见。但归根结底,这并不重要,因为很容易在两者之间切换。

SJLJ

SJLJ在各种架构中得到广泛支持,并且更加健壮。此外,可以通过使用其他异常处理系统(包括C库)的库抛出SJLJ异常。但是,它有性能损失。

SEH

SEH更加高效(无性能损失),但不幸的是受到支持较少。当抛出未使用SEH的库时,SEH异常会导致错误发生。

就您的代码而言,没有真正的区别。如果需要,您可以随时更换编译器。


7
更多解释——虽然在 C 代码中通常不使用异常,但异常是一种处理错误的方法,可以避免不断检查返回代码。这在 C++ 和大多数面向对象的语言中很常见。当遇到错误时,会抛出某种异常类型,然后由其他代码捕获。在 C++ 中,这是一个“实现”问题,这意味着它不是标准,所以不同的编译器可能会有不同的做法。问题在于当程序的不同部分(例如库)以不同方式实现异常处理时会出现混乱。 - nategoose
“@nategoose “这在C++和大多数面向对象的语言中很常见。” 不仅如此,甚至函数式和(是的!)逻辑编程语言也有异常。这就是我们添加一个设施的地方,使程序员能够轻松处理那些需要传递到实际处理它们的某个部分的“异常情况”。 - David Tonhofer

19

我在MinGW-w64中发现了SJLJ和SEH异常处理之间的一个区别:只要在运行时执行了至少一个try{}块,由signal()函数设置的C信号处理程序在SJLJ版本中就无法工作。由于这个问题似乎没有在任何地方被描述,所以我在这里记录一下。

以下示例(test_signals.cpp)演示了这一点。

// This sample demonstrates how try {} block disables handler set by signal()
// on MinGW-w64 with GCC SJLJ build
#include <signal.h>
#include <iostream>

int izero = 0;

static void SIGWntHandler (int signum)//sub_code)
{
  std::cout << "In signal handler, signum = " << signum << std::endl;
  std::cout << "Now exiting..." << std::endl;
  std::exit(1);
}

int main (void)
{
  std::cout << "Entered main(), arming signal handler..." << std::endl;
  if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
    std::cout << "signal(OSD::SetSignal) error\n";
  if (signal (SIGFPE, (void(*)(int))SIGWntHandler) == SIG_ERR)
    std::cout << "signal(OSD::SetSignal) error\n";
  if (signal (SIGILL, (void(*)(int))SIGWntHandler) == SIG_ERR)
    std::cout << "signal(OSD::SetSignal) error\n";

  // this try block disables signal handler...
  try { std::cout << "In try block" << std::endl; } catch(char*) {}

  std::cout << "Doing bad things to cause signal..." << std::endl;
  izero = 1 / izero; // cause integer division by zero
  char* ptrnull = 0;
  ptrnull[0] = '\0'; // cause access violation

  std::cout << "We are too lucky..." << std::endl;
  return 0;
}

使用以下内容进行构建:

g++ test_signals.cpp -o test_signals.exe

预期输出为:

Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...
In signal handler, signum = 8
Now exiting...

当我使用MigGW-w64 SJLJ变体进行构建时,实际输出结果为:

Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...

应用程序在一段时间后静默终止。也就是说,信号处理程序没有被调用。如果注释掉try{}块,则信号处理程序会被正确调用。

当使用MinGW-w64 SEH变体时,它的行为符合预期(信号处理程序被调用)。

我不清楚为什么会出现这个问题,因此如果有人能够给出解释,我将不胜感激。


你最好到MinGW论坛或邮件列表上询问。也有可能在2022年修复了这个问题(5年后)。 - Igor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接