我正在努力尝试以可移植的方式设置std::fenv。

根据this cppreference页面,似乎fesetexceptflag(const std::fexcept_t*,int)应该可以帮助我完成这项工作。另一方面,我发现GNU还提供了feenableexcept(int)函数。我的理解是feenablexcept是GNU特定的,尽管我很可能总是可以访问GNU东西,但我还是希望只使用std东西,即坚持使用fesetexceptflag
我写了一点测试,发现feenableexcept方法行得通,而fesetexceptflag方法行不通。这是两个例子。在main开头的两行中交换注释,以获取版本1(fesetexceptflag)和版本2(feenableexcept):

#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的文档?我的理解是,它会捕获第一个arg中第二个arg中有效的所有位,并将它们放入fenv中(这似乎正在发生)。但是,这似乎无效。另一方面,版本2的mask fenv为0,但成功提高了SIGFPE。我很困惑

我在Linux机器(Red Hat)上使用gcc 8.2.0,如果可以的话。

最佳答案



是。 fesetexceptflag的含义:设置此异常标志以表示已报告异常。
fetestexcept的正确用法是:

feclearexcept(FE_ALL_EXCEPT);
int mask = fetestexcept(FE_ALL_EXCEPT);
printf("current mask: %d\n",mask);
printf("FE_DIVBYZERO before: %s\n",std::fetestexcept(FE_DIVBYZERO) ? "yes" : "no"); // no
double my_inf = one/zero;
int mask = fetestexcept(FE_ALL_EXCEPT);
printf("current mask: %d\n",mask);
printf("FE_DIVBYZERO after: %s\n",std::fetestexcept(FE_DIVBYZERO) ? "yes" : "no"); // yes

没有使浮点异常引发信号的标准方法。这就是glibc为您提供的功能。您可以自己发出信号:
if (fetestexcept(FE_ALL_EXCEPT))
    raise(SIGFPE);

09-08 00:25