2

Stroustrupは、「C ++の設計と進化」(AddisonWesley、1994)で、「算術オーバーフローやゼロ除算などの低レベルのイベントは、例外ではなく、専用の低レベルのメカニズムによって処理されると想定されている」と述べています。これにより、C ++は算術演算に関して他の言語の動作と一致するようになります。また、ゼロ除算などのイベントが非同期である、パイプラインの多いアーキテクチャで発生する問題を回避できます。」

Q1:例外ではない場合、GCCが低レベルのエラーではなく1つを報告するのはなぜですか?

Q2:整数を除算しているのに、なぜ浮動小数点として報告されるのですか?

私はcatch(...)でそれを捕まえることができないので、それは非常に誤解を招きます。明らかに、「エラー」全体をテストして回避することはできますが、私のポイントは、それが例外(合理的)である可能性があると考え、それをキャッチしようとし、それが例外ではないことを発見する初心者にとっては非常に混乱するということです、報告された実行時例外について疑問に思います。

私のコンパイラはgccバージョン4.2.1(Apple Inc.ビルド5666)(ドット3)です

CPU例外、FPU例外、言語例外、OS例外の違いを正確に説明することで、これを解決できる可能性があります。

プログラム例:

int main(){
    int i=1/0;
    return i;
}

結果の出力:

浮動小数点例外

4

4 に答える 4

5

浮動小数点例外(FPE)はC++例外ではありません。さまざまなシステムにはいくつかの種類の例外があり、それらは互換性がありません。FPEは、マイクロプロセッサまたはISAレベルでは例外ですが、C++レベルでは例外です。FPEを使用すると、SIGFPEと呼ばれるシグナルが発生する可能性があります。このシグナルは処理できますが、C++のtry/catchは使用できません。それを処理したい場合は、POSIX関数sigactionを使用できます(Windowsでは構造化例外処理を使用すると思います)。

于 2012-02-20T18:21:06.230 に答える
4

C ++の意味での例外は、ソフトウェアで検出されたエラーです。ゼロで除算すると、通常、問題を検出し、ハードウェア例外(同じ名前、同様の概念、異なる獣)をアサートするハードウェアです。オペレーティングシステムのハードウェア例外ハンドラはこれを受け取り、何をするかを決定します。一般的なOSの反応は、ハードウェア例外時に実行されていたプロセスにシグナルを送信し(システムがユーザーモードで実行されている場合)、そのプロセスのシグナルハンドラーに処理方法を決定させることです。

于 2012-02-20T18:18:32.043 に答える
2

古代の歴史は、浮動小数点エラーとゼロ除算の両方をSIGFPEに折り畳みました。例外を受信すると、それをデコードしてどちらかを判別できますが、シェルはそうではありません。

于 2012-02-20T18:24:51.253 に答える
1

次の小さなプログラムは、浮動小数点エラーをキャッチし、信号に関する情報を出力します。C言語の観点からは、ゼロによる除算は未定義の動作であることに注意してください。たとえば、すべてのシステムにPOSIX信号があるわけではありません。コンパイラーはエラーを簡単に予測できるため、POSIXシステムでも、すべてのコードを単純に削除するか、エラーですぐに終了するかを決定する場合があります。(私は、POSIXシステム上のコンパイラーが期待されることを実行するプログラムを生成することを期待し、想定します。その下では実行されます。しかし、そのような期待は以前はがっかりしました。)

#include <stdio.h>
#include <signal.h>
#include <stdlib.h> // for exit()

void fpehandler (int sig, siginfo_t *info, void *uc) 
{
    fprintf (stderr, 
            "Caught signal no. %d; code: %d (FPE_INTDIV would be %d)\n", 
            sig, info->si_code, FPE_INTDIV);
    if(info->si_code == FPE_INTDIV)
    {
        fprintf (stderr, 
                "Yes, the error was an integer division by zero.\n");
    }

    // It's not officially safe to return from a handler
    // of a "program error signal" (of which SIGFPE is an example).
    // Plus many functions are not strictly safe to 
    // call in a signal handler (e.g. exit()).
    // See https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers .
    // We call _Exit().
    _Exit(0); // success, isn't it?
}

int main(void)
{
    struct sigaction sa;
    sigemptyset (&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = fpehandler;
    sigaction (SIGFPE, &sa, NULL);

    // cause "floating point" error 
    printf("%d\n", 2/0);

    // ---- below is unreachable code ;-) ----------

    // We shouldn't be here. Something went wrong. return 1.
    return 1;            
}

cygwin、gcc 5.4.0で実行すると、次のように出力されます。

$ gcc -Wall float-except.c -o float-except && ./float-except
float-except.c: In function 'main':
float-except.c:28:21: warning: division by zero [-Wdiv-by-zero]
     printf("%d\n", 2/0);
                     ^
Caught signal no. 8; code: 15 (FPE_INTDIV would be 15)
Yes, the error was an integer division by zero.
于 2016-10-25T16:57:42.577 に答える