Я прошу прощения за то, что задал вопрос, который задавался много раз прежде. Но после нескольких поисков я понимаю, что у меня может возникнуть фундаментальное недопонимание между тем, как FPE должны обрабатываться в C / 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 часто используется для вызова кода на фортране), кажется неудобным иметь некоторые предварительные знания о том, где могут возникать исключения.
Нет ли в C простого способа получить код, который останавливается при первом появлении исключения? Или есть другая парадигма, когда дело доходит до обработки исключений в C, которую я до конца не понимаю?
Поскольку вы используете утилиты 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
В следующем коде я покажу, как сделать именно то, что я стремился сделать с моим вопросом выше. Он опирается на упомянутое расширение 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);
}