2016-06-14 2 views
1

Я хочу, чтобы мой код завершился при ошибке с плавающей запятой. В linux-gcc функция feenableexcept() выполняет задание, но недоступна в OSX. При использовании gcc на OS X подход, принятый в (Enabling floating point interrupts on Mac OS X Intel), отлично работает при использовании gcc, но не работает при использовании clang.Как включить исключения с плавающей запятой для clang в OS X?

Пример кода:

#include <stdio.h> 
#include <execinfo.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <iostream> 
#include <xmmintrin.h> 

void handler(int sig) { 
    void *array[10]; 
    size_t size; 
    size = backtrace(array, 10); 
    fprintf(stderr, "Error: signal %d:\n", sig); 
    backtrace_symbols_fd(array, size, STDERR_FILENO); 
    exit(1); 
} 

int main(int argc, char **argv) 
{ 
    _MM_SET_EXCEPTION_MASK((_MM_EXCEPT_INVALID | 
       _MM_EXCEPT_DENORM | 
       _MM_EXCEPT_DIV_ZERO | 
       _MM_EXCEPT_OVERFLOW | 
       _MM_EXCEPT_UNDERFLOW | 
       _MM_EXCEPT_INEXACT)); 

    signal(SIGSEGV, handler); 
    signal(SIGFPE, handler); 

    std::cout<<"Perform 1.0/0.0"<<std::endl; 
    double a = 1.0/0.0; 
    std::cout<<"1.0/0.0 didn't kill program, result is "<<a<<std::endl<<std::endl; 

    int* foo = (int*) - 1 ;// make a bad pointer 
    std::cout<<"Attempting to print a bad pointer"<<std::endl; 
    printf("%d\n", *foo); 
    std::cout<<"Bad pointer didn't kill program."<<std::ends; 
} 

При скомпилированы с использованием gcc5, результат:

Perform 1.0/0.0 
Error: signal 8: 
0 a.out        0x000000010f97cb7f _Z7handleri + 28 
1 libsystem_platform.dylib   0x00007fff895c652a _sigtramp + 26 
2 ???         0x00007fff6eab6568 0x0 + 140735050114408 
3 libdyld.dylib      0x00007fff936a15ad start + 1 

Замечательно. Прекрасно работает. Однако, при компиляции с использованием лязга (Apple LLVM версии 7.3.0 (лязг-703.0.29)) результат заключается в следующем:

Perform 1.0/0.0 
1.0/0.0 didn't kill program, result is inf 

Attempting to print a bad pointer 
Error: signal 11: 
0 a.out        0x000000010d501d1f _Z7handleri + 31 
1 libsystem_platform.dylib   0x00007fff895c652a _sigtramp + 26 
2 ???         0x00007fff62b7e568 0x0 + 140734849607016 
3 libdyld.dylib      0x00007fff936a15ad start + 1 

Не велик. Не поднимал FPE, и код просто продолжал напрягаться. Я огляделся и не могу найти, как получить clang, чтобы поднять FPE. У кого-нибудь есть опыт? Благодаря!

+0

Возможный дубликат [Включение с плавающей точкой прерывания на Mac OS X Intel] (http://stackoverflow.com/questions/247053/enabling-floating-point-interrupts-on- mac-os-x-intel) – nwellnhof

+0

@nwellnhof подход в связанном вопросе не работает с clang. – doc07b5

ответ

0

Вы устанавливаете маскированные исключения. Таким образом, вы должны очистить бит, если вы хотите, чтобы получить исключение:

_MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() 
     & ~(_MM_EXCEPT_INVALID | 
      _MM_EXCEPT_DENORM | 
      _MM_EXCEPT_DIV_ZERO | 
      _MM_EXCEPT_OVERFLOW | 
      _MM_EXCEPT_UNDERFLOW | 
      _MM_EXCEPT_INEXACT)); 
+0

Вставьте этот ответ в код, и он не работает ни для g ++, ни для clang ++. Это сработало для вас? Есть ли ссылка на уровень intro, о которой вы знаете, объясняет, как работают эти битовые поля? – doc07b5

+0

Я набрал его в своем браузере, поэтому я не тестировал его. Разве вы не получили исключений? Вы можете найти ссылку на googling '_MM_SET_EXCEPTION_MASK'. Что вы подразумеваете под «этими битпольными работами»? В общем или в частности к маскам исключения? –

+0

Я не получил исключение с плавающей запятой. У меня googled _MM_SET_EXCEPTION_MASK, и подходы, которые я нашел, работают с gcc, но не с clang. Что я подразумеваю под «этими битовыми полями»? как интерпретируется битовое поле? Есть ли карта битового поля? Является ли он зависимым от платформы или зависит от компилятора? Я думаю, что это то, что должно быть легко найти, но я ничего не могу найти. Может быть, я просто должен это знать? – doc07b5

0

Принятый подход, кажется, новый заголовок для встроенного проекта, включает в себя. Для Linux этот файл будет проигнорирован и просто отброшен на запас fenv.h.

Этот код является кредитом 2009, David N. Williams, заимствованным дословно из проекта ardupilot, который был первым результатом, который я смог найти. Я могу подтвердить это на MacOS 10.13 с Apple LLVM version 9.0.0 (clang-900.0.39.2).

Примечание: Обратите внимание, хотя многие предложения я видел рекомендую однозначно назвать этот заголовок для ясности, во многом это напоминает мне о polyfill (срок от JS/Webdev), так имитируя, что идеология проекта код заимствован, так как мой собственный проект сохранил его имена fenv.h. Переименуйте при необходимости.

fenv.h

#pragma once 

#include_next <fenv.h> 

#if defined(__APPLE__) && defined(__MACH__) 

// Public domain polyfill for feenableexcept on OS X 
// http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c 

inline int feenableexcept(unsigned int excepts) 
{ 
    static fenv_t fenv; 
    unsigned int new_excepts = excepts & FE_ALL_EXCEPT; 
    // previous masks 
    unsigned int old_excepts; 

    if (fegetenv(&fenv)) { 
     return -1; 
    } 
    old_excepts = fenv.__control & FE_ALL_EXCEPT; 

    // unmask 
    fenv.__control &= ~new_excepts; 
    fenv.__mxcsr &= ~(new_excepts << 7); 

    return fesetenv(&fenv) ? -1 : old_excepts; 
} 

inline int fedisableexcept(unsigned int excepts) 
{ 
    static fenv_t fenv; 
    unsigned int new_excepts = excepts & FE_ALL_EXCEPT; 
    // all previous masks 
    unsigned int old_excepts; 

    if (fegetenv(&fenv)) { 
     return -1; 
    } 
    old_excepts = fenv.__control & FE_ALL_EXCEPT; 

    // mask 
    fenv.__control |= new_excepts; 
    fenv.__mxcsr |= new_excepts << 7; 

    return fesetenv(&fenv) ? -1 : old_excepts; 
} 

#endif