2

我很抱歉问了一个以前被问过很多次的问题。但是经过几次搜索,我意识到我可能对如何在 C/C++ 中处理 FPE 与如何在 Fortran 中处理它们之间存在根本性的误解。

在 Fortran(准确地说是 GNU fortran)中,如果想要捕获浮点异常(例如使用 NAN),编译器标志 -ffpe-trap=invalid 可以解决问题。一旦执行了违规语句,就会引发浮点异常。

然而,在 C (GNU gcc) 中,情况似乎并非如此。更令人讨厌(但也许并不奇怪)是相同的 fortran 代码,当从 C 主程序调用时不会引发异常(并停止执行),而当从 Fortran 主程序调用时会引发异常。这似乎与是否使用 C 或 gfortran 链接器无关。

经过大量搜索和阅读,我发现 fenv.h 中提供了 C/C++ 功能,这表明了处理异常的“C 方式”。我看到我可以设置异常标志,然后检查是否引发了异常。我可以看到这种方法如何为异常处理方式提供更多灵活性。这是在 C 中处理异常的“最佳实践”方式吗?对于科学编程(通常使用 C 来调用 fortran 代码),必须对可能发生异常的位置有一些高级知识似乎很不方便。

C 语言中是否没有(直接的)方法可以让代码在第一次出现异常时停止?或者当涉及到 C 中的异常处理时,我还没有完全掌握另一种范式吗?

4

2 回答 2

2

由于您使用 GNU 实用程序,我假设您使用的是 *nix。您需要启用浮点异常。完成后,使用信号传递异常。下面的代码说明了这一点:

#include <fenv.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void handler(int sig) {
    printf("Floating Point Exception\n");
    exit(0);
}


int main(int argc, char ** argv) {
    feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
    signal(SIGFPE, handler);

    float a = 42.0, b = 0.0, res;

    res = a / b;

    return 0;
}

与 libm 的链接:

gcc -o test test.c -lm

在 Windows 上,我相信您需要使用结构化异常处理程序:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms680657 (v=vs.85).aspx

于 2013-07-04T15:05:05.437 回答
0

在下面的代码中,我展示了如何完全按照我的目标来处理上面的问题。它依赖于此处提到的 Mac OSX 扩展此处描述的信号值 。

我不是这两个主题的专家,所以不能断言这段代码的可移植性。但它确实做了我想要的两件事:它允许我将数据初始化为“NAN”,然后捕获这些未初始化值的无效使用。正常执行和 gdb 都会检测到陷阱。

我当然会感谢对此解决方案的任何评论。


#include "fp_exception_glibc_extension.h"
#include <fenv.h>
#include <signal.h>
#include <stdio.h>

/*
-----------------------------------------------------------------------
This example illustrates how to initialize data with an sNAN.  Later, if
the data is used in its 'uninitialized' state, an exception is raised,
and execution halts.

The floating point exception handler 'fp_exception_glibc_extension' is
 needed for OS X portability.

 At least two blog posts were used in writing this :

 "Update: Floating-point exception handling on Mac OS X"
 http://philbull.wordpress.com/2012/12/09/update-floating-point-exception-handling-on-mac-os-x/
 Note : there is a lengthy email exchange about how portable this extension is;  see
 comments in the text of the code.

 "NaNs, Uninitialized Variables, and C++"
 http://codingcastles.blogspot.fr/2008/12/nans-in-c.html
 -----------------------------------------------------------------------
*/

void set_snan(double& f)
{
    *((long long*)&f) = 0x7ff0000000000001LL;
}

int main()
{
    /* On OS X, this extension is provided by 
       'fp_exception_glibc_extension.{c,h} */
    feenableexcept(FE_INVALID);

    double p;
    set_snan(p); /* Initialize to signaling nan */

    double q;
    q = 2*p;     /* Floating point exception is trapped here */
    printf("p = %f; q = %f\n",p,q);
}
于 2013-07-05T07:38:14.080 回答