В некоторых linux системах вместо исключения в операции с плавающей точкой (сигнал SIGFPE) появляется значение NaN и вероятность отыскать ошибку близка к нулю и о существовании ошибки можно лишь догадываться, когда в конце появилось NaN. Хотелось бы, чтобы такое проблемное место убивало программу (тогда отладчик может помочь отыскать проблемное место). Собственно говоря, суть вопроса в том, как сделать, что бы ошибка в операции с плавающей точкой приводила к SIGFPE.
В реализации libc от GNU есть нестандартная функция feenableexcept()
¹. Она же есть и во многих других libc (в том числе {Free,Open}BSD и uclibc). В качестве аргумента она принимает битовую маску исключительных ситуаций (аналогично fesetexceptflag()
и др.):
FE_DIVBYZERO
— деление на нольFE_OVERFLOW
— переполнениеFE_UNDERFLOW
— обратное переполнениеFE_INEXACT
— неточный результатFE_INVALID
— неверная операцияВсе эти макросы определены только если платформа их поддерживает. Также определён макрос FE_ALL_EXCEPT
, который представляет комбинацию всех вышеописанных.
Также для отмены сигнала есть fedisableexcept()
.
Как и многие другие расширения GNU, они требует определения features-test макроса _GNU_SOURCE
до включения каких-либо системных хедеров. К сожалению, в Linux man-pages обе эти функции слабо документированы: о ней упомянуто только вскользь в man fenv
. , так что за какими-то подробностями лучше обратиться к исходникам и/или к справке из других ОС.
К сожалению, после получения SIGFPE
восстановить нормальную работу непосредственно с точки возникновения сигнала невозможно, так что останется только завершиться (или сделать longjmp()
, см. комментарии). Так что, пожалуй, данные функции ограничены к использованию только отладкой. Возврат из обработчика сигнала приведёт к зацикливанию т.к. выполнение продолжится с той же инструкции, которая вызвала ошибку.
Эти функции работают без какой-либо магии со стороны компилятора или системы. Всё завязано исключительно на возможности процессора. На x86 просто устанавливаются соответствующие биты в управляющем регистре CW
для x87 и, при возможности, в MXCSR
для SSE (см. FLDCW
и LDMXCSR
соответственно). Далее при определении соответствующей ситуации процессор просто выкинет исключение, которое обработает ядро и отправит сигнал текущему процессу.
Подсказка: дабы получить разные ошибки, нужно раскомментировать строки в конце:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fenv.h>
#include <unistd.h>
#include <signal.h>
#define BUF_SZ 1024
void sigfpe_hdl(int signum, siginfo_t *si, void *ctx) {
if (signum == SIGFPE) {
char buf[BUF_SZ];
char *msg;
switch (si->si_code) { /* see `man 2 sigaction` for the list */
case FPE_INTDIV: msg = "Integer divide by zero" ; break;
case FPE_INTOVF: msg = "Integer overflow" ; break;
case FPE_FLTDIV: msg = "Floating-point divide by zero" ; break;
case FPE_FLTOVF: msg = "Floating-point overflow" ; break;
case FPE_FLTUND: msg = "Floating-point underflow" ; break;
case FPE_FLTRES: msg = "Floating-point inexact result" ; break;
case FPE_FLTINV: msg = "Floating-point invalid operation"; break;
case FPE_FLTSUB: msg = "Subscript out of range" ; break;
default: msg = "Unknown FPE";
}
char *msgend=buf;
msgend = stpncpy (msgend,"Received SIGFPE. Reason: ", BUF_SZ - (msgend-buf));
msgend = stpncpy (msgend, msg, BUF_SZ - (msgend-buf));
msgend = stpncpy (msgend, ".\n", BUF_SZ - (msgend-buf));
write (STDERR_FILENO, buf, msgend - buf);
}
exit (EXIT_FAILURE);
}
int main() {
struct sigaction sa_fpe = {
.sa_sigaction = sigfpe_hdl,
.sa_flags = SA_SIGINFO,
};
sigaction (SIGFPE, &sa_fpe, 0);
feenableexcept (FE_ALL_EXCEPT);
int i,j;
// i=10; j=0; i=i/j; // integer divide by zero
float x, y;
// x = 10.0; y= 0.0; x = x/y; // divide by zero
// x = 1e+25; y= 1e+25; x = x*y; // overflow
// x = 1e-25; y= 1e-25; x = x*y; // underflow
// x = 0.2; y= 0.1; x = x+y; // inexact result
// x = 0.0; y= 0.0; x = x/y; // invalid operation
}
¹ Аналогичного результата можно добиться с помощью стандартных fegetenv()
+fesetexceptflag()
+fsetenv()
.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
По ходу выполнения программы возникает исключение "Необработанное исключение по адресу 0x79E917D7 (ucrtbaseddll) в ConsoleApplication7
Написал код, согласно требованиям (задание приложу в скриншоте)Все вычисляет,ошибок не выдает, однако значение проверки суммы ряда отличается...
Какая функция, описание которой находится в заголовочном файле windowsh (насколько я знаю, она там), отвечает за автозапуск и как прописать, заранее...