web-dev-qa-db-ja.com

MinGW SEHとMinGW SJLJの違いは何ですか?

私はCを学び始め、今QT x64をインストールしています(ここにフォーム: http://tver-soft.org/qt64 )。インストールには2つのオプションがあります:MinGW 4.9.2 SEHまたはMinGW 4.9.2 SJLJ
質問:どちらをインストールするのが良いのですか、それはなぜですか?

読んだ sjljとdwarfとsehの違いは何ですか?https://wiki.qt.io/MinGW-64-bit#Exception_handling:_SJLJ .2C_DWARF.2C_and_SEH しかし、何も理解していません(Cおよびコンパイラ言語の新機能)。

26
vasili111

SJLJとSEHは、2つの異なる例外処理システムです。

特定の違いについては、すでに見たリソースがすべてをカバーしています。

ただし、どちらがbetterのインストールに適しているかについては、 sEHが必要であることを知らない限り、[〜#〜] sjlj [〜#〜]を使用してください。

2019 Update:最近のシステムでは、SJLJを使用する理由はないので、上記のアドバイスはおそらく反転させる必要があります。 SEHはより一般的になりました。ただし、この2つを簡単に切り替えることができるので、結局は問題ではありません。

SJLJ

SJLJは、アーキテクチャ全体でより広くサポートされており、より堅牢です。また、SJLJ例外は、Cライブラリを含む他の例外処理システムを使用するthroughライブラリをスローできます。ただし、パフォーマンスが低下します。

SEH

SEHの方がはるかに効率的ですが(パフォーマンスが低下することはありません)、残念ながら十分にサポートされていません。 SEH例外を使用すると、SEHを使用しないライブラリを介してスローされると、問題が発生します。

コードに関する限り、実際の違いはありません。必要に応じて、後でいつでもコンパイラを切り替えることができます。

26
Apples

MinGW-w64でのSJLJとSEHの例外処理の1つの違いを発見しました。signal()関数によって設定されたCシグナルハンドラーは、実行時に少なくとも1つのtry {}ブロックが実行されるとすぐに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バリアントを使用すると、期待どおりに動作します(シグナルハンドラーが呼び出されます)。

なぜこの問題が発生するのかはっきりしないので、誰かが説明してくれるとありがたいです。

12
Andrey Betenev