2

std::fenv をポータブルな方法で設定しようとして苦労しています。

このcppreference ページに基づいて、それはfesetexceptflag(const std::fexcept_t*,int)私がトリックを行うのに役立つはずです. 一方で、GNU にもそのfeenableexcept(int)機能があることを知りました。私の理解では、それfeenablexceptはGNU固有のものであり、常にGNUのものにアクセスできる可能性が非常に高いですが、stdのものだけを使用したいと思っていましたfesetexceptflag。私は小さなテストを書きましたが、feenableexceptアプローチは機能しますが、fesetexceptflag機能しないことがわかりました。2 つの例を次に示します。fesetexceptflagバージョン 1 ( ) とバージョン 2 ( feenableexcept)を取得するには、main の先頭にある 2 行のコメントを入れ替えます。

#include <cfenv>
#include <csignal>
#include <cstdio>

void signal_handler (int signum) {
  printf ("signal %d caught.\n",signum);
  exit(1);
}

int main(int,char**){
  std::fexcept_t my_flag = FE_DIVBYZERO;
  fesetexceptflag(&my_flag,FE_ALL_EXCEPT); // Uncomment this for version 1
  // feenableexcept(my_flag); // Uncomment this for version 2

  int mask = fetestexcept(FE_ALL_EXCEPT)
  printf("current mask: %d\n",mask);
  printf("mask is FE_DIVBYZERO: %s\n",mask==FE_DIVBYZERO ? "yes" : "no");
  signal(SIGFPE, signal_handler);

  double one  = 1.0;
  double zero = 0.0;
  double my_inf = one/zero;
  printf("All done!\n");
  return 0;
}

バージョン 1 の出力:

current mask: 4
mask is FE_DIVBYZERO: yes
All done!

バージョン 2 の出力:

current mask: 0
mask is FE_DIVBYZERO: no
signal 8 caught.

したがって、バージョン 1 は fenv で例外フラグを正しく設定しているように見えますが、SIGFPE の発生に失敗しますが、バージョン 2 は例外フラグを設定しませんが、SIGFPE を発生させます。ここで何が起こっているのですか?のドキュメントを誤解していますfesetexceptflagか? 私の理解では、2番目の引数でアクティブな最初の引数のすべてのビットを取得し、それらをfenvに入れます(これが起こるようです)。しかし、それでは効果がないようです。一方、バージョン 2 はマスク fenv が 0 ですが、SIGFPE を上げることに成功しています。私はとても混乱しています。

Linux マシン (Red Hat) で gcc 8.2.0 を使用しています。

4

2 に答える 2