MinGW SEH 和 MinGW SJLJ 有啥区别?

Posted

技术标签:

【中文标题】MinGW SEH 和 MinGW SJLJ 有啥区别?【英文标题】:What is the difference between MinGW SEH and MinGW SJLJ?MinGW SEH 和 MinGW SJLJ 有什么区别? 【发布时间】:2015-08-24 16:30:13 【问题描述】:

我刚刚开始学习 C 并现在安装 QT x64(此处为:http://tver-soft.org/qt64)。我有两个安装选项:MinGW 4.9.2 SEHMinGW 4.9.2 SJLJ问题:哪个更好安装?为什么?

我读过What is difference between sjlj vs dwarf vs seh? 和https://wiki.qt.io/MinGW-64-bit#Exception_handling:_SJLJ.2C_DWARF.2C_and_SEH,但什么都不懂(C 和编译器语言的新手)。

【问题讨论】:

对于投票结束这个问题的人来说,这对于一个新手程序员来说是完全合理的事情。两个版本的 MinGW 之间的差异完全基于新用户无法理解的概念。 【参考方案1】:

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

对于具体的区别,你已经看到的资源涵盖了一切。

但是,至于安装哪个更好选择SJLJ,除非你知道你需要SEH。

2019 年更新:在现代系统上,没有理由使用 SJLJ,因此可能应该推翻上述建议。 SEH现在更常见。最终,这并不重要,因为很容易在两者之间切换。

SJLJ

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

SEH

SEH 效率更高(没有性能损失),但遗憾的是没有得到很好的支持。当通过不使用 SEH 的库抛出 SEH 异常时,会导致不好的事情发生。

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

【讨论】:

更多解释 -- 虽然 C 代码中通常不使用异常,但异常是一种无需不断检查返回码即可处理错误的方法。这在 C++ 和大多数面向对象的语言中很常见。当遇到错误时,会“抛出”异常类型,然后被其他代码捕获。在 C++ 中,这是一个“实现”问题,这意味着它不是一个标准,因此不同的编译器可以以不同的方式处理它。当程序的不同部分(即库)以不同方式实现异常时,就会出现问题。 @nategoose “这在 C++ 和大多数面向对象语言中很常见。” 不仅如此,即使是函数式和(是的!)逻辑编程语言也有例外。在这里,我们安装了一个工具,使程序员可以轻松处理那些需要投入到可以实际处理它们的部分的“异常情况”。【参考方案2】:

我在 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 SEH 和 MinGW SJLJ 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

sjlj vs dwarf vs seh 有啥区别?

mingw-gcc-8.3.0-i686-posix-sjlj

mingw-gcc-9.3.1-i686-posix-sjlj-20200315-6c7e43f

mingw-gcc-10.0.1-experimental-i686-posix-sjlj-20200202-0303907

数据结构与算法基本概念

mingw w64 安装问题