Есть ли способ сказать gcc выбросить SIGFPE или что-то подобное в ответ на вычисление, которое приводит к NaN
или (-)inf
во время выполнения, например, для деления на нуль?
Я пробовал флаг -fsignaling-nans
, который, похоже, не помогает.
Есть ли способ сказать gcc выбросить SIGFPE или что-то подобное в ответ на вычисление, которое приводит к NaN
или (-)inf
во время выполнения, например, для деления на нуль?
Я пробовал флаг -fsignaling-nans
, который, похоже, не помогает.
Почти любая операция с плавающей запятой или функция математической библиотеки, которая генерирует NaN из не-NaN-входов, также должна сигнализировать исключение с плавающей запятой "недействительная операция"; Аналогично, расчет, который создает бесконечность с конечных входов, обычно сигнализирует об исключении с плавающей запятой "divide-by-zero" или "overflow". Поэтому вы хотите каким-то образом превратить эти исключения в SIGFPE.
Я подозреваю, что ответ будет сильно зависящим от системы, поскольку управление ловушками и флагами с плавающей запятой, скорее всего, будет поставляться библиотекой платформы C, а не самой gcc. Но вот пример, который работает для меня, в Linux. Он использует функцию feenableexcept
от fenv.h
. Для объявления этой функции необходимо определить _GNU_SOURCE
.
#define _GNU_SOURCE
#include <fenv.h>
int main(void) {
double x, y, z;
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
x = 1e300;
y = 1e300;
z = x * y; /* should cause an FPE */
return 0;
}
Оговорка. Я думаю, что с некоторыми настройками можно предположить, что исключение фактически не генерируется до следующей операции с плавающей запятой после той, которая (теоретически) должна была вызвать ее, поэтому вам иногда требуется no-op floating (например, умножение на 1.0) для запуска исключения.
В MinGW 4.8.1 (GCC для Win32) Я вижу, что feenableexcept
не определен. Обходным путем является использование платформы Win32 _controlfp
, таким образом:
#undef __STRICT_ANSI__ // _controlfp is a non-standard function documented in MSDN
#include <float.h>
#include <stdio.h>
int main()
{
_clearfp();
unsigned unused_current_word = 0;
// clearing the bits unmasks (throws) the exception
_controlfp_s(&unused_current_word, 0, _EM_OVERFLOW | _EM_ZERODIVIDE); // _controlfp_s is the secure version of _controlfp
float num = 1.0f, den = 0.0f;
float quo = num / den;
printf("%.8f\n", quo); // the control should never reach here, due to the exception thrown above
}