ゼロ除算の結果生じるSIGFPEを無視できますか?
-
03-07-2019 - |
質問
特定の状況で停止するために、意図的にゼロによる除算を実行する(および結果を揮発性変数に格納する)プログラムがあります。ただし、ゼロによる除算を実行するマクロを変更せずに、この停止を無効にできるようにしたいと思います。
無視する方法はありますか?
使用してみました
#include <signal.h>
...
int main(void) {
signal(SIGFPE, SIG_IGN);
...
}
ただし、メッセージ「浮動小数点例外(コアダンプ)」で死にます。
実際には値を使用しないため、変数に何が割り当てられているかはあまり気にしません。 0、ランダム、未定義...
編集:これは最もポータブルではないことはわかっていますが、多くの異なるOSで実行される組み込みデバイス向けです。デフォルトの停止アクションは、ゼロで除算することです。他のプラットフォームでは、ウォッチドッグによる再起動を強制するためにさまざまなトリックが必要です(割り込みを無効にした無限ループなど)。 PC(Linux)テスト環境では、アサートなどに依存せずにゼロ除算の停止を無効にしたかった。
解決
なぜゼロによる除算を意図的に実行して停止するのですか? exit(-1)
またはそれに相当するものはありませんか?
特に0による除算の結果が必要ない場合、これは意味がありません。
他のヒント
さて、最初に、非推奨の signal()
の代わりに sigaction(2)を使用する必要があります。
第二に、プログラムを終了する目的でSIGFPEを使用することは、ばかげたことです。副作用のために他の信号をju審し、セマンティック値を無視する代わりに、SIGTERMやSIGUSR1などの信号を上げる必要があります。より具体的には、 sigaction(2)のmanページには、使用目的が壊れている1つまたは2つの方法を示すSIGFPEに関する宣伝文を含むNOTESセクションがあります。
やるべきことは、終了したいときにシグナルを raise(3)することです。次に、 sigaction
構造体の sa_handler
フィールドを使用して、無視する( SIG_IGN
)か終了する( SIG_DFL
)かを変更します)その信号で。
int main(void) { struct sigaction my_action; my_action.sa_handler = SIG_IGN; my_action.sa_flags = SA_RESTART; sigaction(SIGUSR1, &my_action, NULL); raise(SIGUSR1); /* Ignored */ my_action.sa_handler = SIG_DFL; sigaction(SIGUSR1, &my_action, NULL); raise(SIGUSR1); /* Terminates */ return 0; }
とはいえ、単純な exit()
ではなくシグナルを使用する理由はわかりません。
の戻り値を確認します
signal(SIGFPE, SIG_IGN);
SIG_ERR
を受け取った場合は、 errno
の値を確認して、何が問題であったかを見つけてください。これは移植性のあることです。
ゼロによる除算を変更したくないのは知っていますが、移植性がなく直感に反します。何らかの条件が発生した場合にコアダンプしたいのですが、コードを編集せずにこの動作を無効にできますか? assert
および NDEBUG
を使用します。
これは移植性がありませんが、x86ではFPUを制御することで可能です:
Linuxでgccを使用する(他のコンパイラにも同様の機能があるはずです):
#include <fpu_control.h>
_FPU_SETCW (_FPU_DEFAULT);
_FPU_DEFAULTのデフォルトは_FPU_MASK_ZMに設定されているため(ZMはZero-Divide-Maskを表します)。
void handler(int trapId)
{
// Whatever
}
signal(SIGFPE, handler);
より不自然な式でプログラムを終了させますか?例えば:
#include <signal.h>
#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif
プログラムの他の部分が意図せずにゼロで除算されないように、デフォルトの動作をオーバーライドするのをためらいます。あるいは、コアダンプを取得するためにこの方法で強制的に終了する場合は、デバッガー内でブレークポイントを使用することを検討してください。または、gdbデバッガーを搭載したシステムを使用している場合、gcoreユーティリティが役立つ場合があります。
クラッシュするコードを制御できる場合は、コードを変更して他の方法で死ぬこともお勧めします。そうでない場合は、代わりに空のシグナルハンドラをインストールしようとすることができます(つまり、 signal(SIGFPE、&amp; EmptyFunction
)を使用します)が、未定義の動作に依存しているため、保証はありません他のシステム、または他のカーネルまたはCライブラリバージョンでも動作します。
クラッシュするコードを無視して、コードを変更して他の方法で死ぬこともお勧めします。そうでない場合は、インストールを試みることができます