Подтвердить что ты не робот

Могу ли я заставить gcc сказать мне, когда вычисление приводит к NaN или inf во время выполнения?

Есть ли способ сказать gcc выбросить SIGFPE или что-то подобное в ответ на вычисление, которое приводит к NaN или (-)inf во время выполнения, например, для деления на нуль?

Я пробовал флаг -fsignaling-nans, который, похоже, не помогает.

4b9b3361

Ответ 1

Почти любая операция с плавающей запятой или функция математической библиотеки, которая генерирует 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) для запуска исключения.

Ответ 2

В 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
}