2

对于提出以前多次提出的问题,我表示抱歉。但是经过多次搜索之后,我意识到我可能会在C/C++中处理FPE与在Fortran中处理它们的方式之间产生根本的误解。在混合C/Fortran代码中捕获浮点异常

在Fortran(确切地说是GNU fortran)中,如果想捕获一个浮点异常(例如使用NAN),编译器标志-ffpe-trap = invalid会执行这个技巧。一旦违规语句被执行,就会引发浮点异常。但是,在C(GNU gcc)中,似乎并不是这种情况。更令人讨厌的是(但也许并不奇怪),相同的fortran代码在从C main调用时不会引发异常(并暂停执行),而在Fortran主程序中调用时则会执行该代码。这似乎与使用C或gfortran连接子无关。

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

C中有没有(简单的)方法让代码在第一次出现异常时暂停?或者在C语言中的异常处理方面还有另外一个范例,那就是我没有完全掌握?

+0

我运行OS X. – Donna

+0

原来'feenableexcept()'是非标准。 [这个问题的答案](http://stackoverflow.com/questions/247053/enabling-floating-point-interrupts-on-mac-os-x-intel)有一些建议和[本博客文章](http: //philbull.wordpress.com/2012/12/09/update-floating-point-exception-handling-on-mac-os-x/)指向一些适用于Linux和Mac OS X的代码。 –

+0

是的,我发现这篇文章和被引用的代码似乎正是我所希望的。您是否对所描述的扩展是否合理? – Donna

回答

0

在下面的代码,我将展示如何确实按照我上面提到的问题来做。它依赖于所提及的Mac OSX扩展here和描述的信号值 here

我不是这两个主题的专家,所以不能声称这个代码是多么便携。但它确实做了我想要的两件事:它允许我将数据初始化为“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); 
} 
+1

这里需要使用'set_snan' 。在程序中稍后使用时,初始化math.h中提供的NAN宏的值不会被捕获。 – Donna

1

既然你使用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

+0

我正在运行OS X,其中feenableexcept不可用。但我刚刚遇到了这个扩展,事实证明我正是想做的。 [OSX_fpe_fix](http://philbull.wordpress.com/2012/12/09/update-floating-point-exception-handling-on-mac-os-x/) – Donna