1

奇妙な動作を見つけたときに、C でのシグナル処理を学ぼうとしました。
x /= y の場合。メイン関数のコンテキストで実行されると、シグナル ハンドラが機能します。しかし、いくつかの関数 (bad_func) ハンドラーで実行された同じものは無視されますが、SIGFPE のシグナルハンドラーは既に設定されています。

Q: _control87 が呼び出されても、SIGFPE がグローバル シグナル ハンドラによって関数に捕捉されなかったのはなぜですか?

(MS VC 2010):

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <float.h>

jmp_buf g_jb_MainFunc;

void hook_zd (int i)
{
    printf("Result :%i\n",i);
    longjmp(g_jb_MainFunc, 5);
}
void bad_func(void)
{
    double x = 0., y = 0.;
    puts("hello1");
    //abort();
    x /= y;
    puts("bye1");
}
int main(int argc, char* argv[])
{
    double x = 0., y = 0.;
    signal(SIGFPE, hook_zd);
    signal(SIGABRT, hook_zd);
    puts("hello");
    _control87(0, _MCW_EM );
    int res;
    if (! (res = setjmp(g_jb_MainFunc)))
    {
        //abort();
        //x /= y;
        bad_func();
    } else
    {
        printf("Jumped here from: %i\n",res);
    }
    puts("bye");

    return 0;
}
4

1 に答える 1

3

最適化をオンにしてコンパイルしない限り、うまくいきます。たとえば、コマンドラインから としてコンパイルするとcl mysigtest.cpp、例外は期待どおりに機能します。しかし、コンパイルするとcl /O1 mysigtest.cpp、例外は表示されません。

逆アセンブルされたコードは問題を示しています。

?bad_func@@YAXXZ (void __cdecl bad_func(void)):
  00000000: 68 00 00 00 00     push        offset ??_C@_06CKBHOFLC@hello1?$AA@
  00000005: E8 00 00 00 00     call        _puts
  0000000A: 68 00 00 00 00     push        offset ??_C@_04EEFJMNKA@bye1?$AA@
  0000000F: E8 00 00 00 00     call        _puts
  00000014: 83 C4 08           add         esp,8
  00000017: C3                 ret

分割は最適化されています。最適化をオフにして試すかbad_func、次のように変更してください。私にとって、それはオプティマイザーを「打ち負かしました」:

double bad_func(double y)
{
    double x = 0.; 
    puts("hello1");
    //abort();
    x /= y;
    puts("bye1");
    return x;
}

そして、それへの呼び出しを変更します:

bad_func( 0.0 );
于 2010-06-23T21:43:10.817 に答える