2013-11-08 3 views
13

Я использую библиотеку C++ JPEG (libjpeg), и я понял, что когда некоторые функции сбой вызывается exit() и приложение закрывается. Как я могу отменить это поведение и предотвратить закрытие приложения при ошибках libjpeg?Обработка ошибок в libjpeg

ответ

19

Это поведение по умолчанию libjpeg. Для того, чтобы обрабатывать ошибки с libjpeg, вы должны определить процедуру обработки ошибок в так:

struct jpegErrorManager { 
    /* "public" fields */ 
    struct jpeg_error_mgr pub; 
    /* for return to caller */ 
    jmp_buf setjmp_buffer; 
}; 
char jpegLastErrorMsg[JMSG_LENGTH_MAX]; 
void jpegErrorExit (j_common_ptr cinfo) 
{ 
    /* cinfo->err actually points to a jpegErrorManager struct */ 
    jpegErrorManager* myerr = (jpegErrorManager*) cinfo->err; 
    /* note : *(cinfo->err) is now equivalent to myerr->pub */ 

    /* output_message is a method to print an error message */ 
    /*(* (cinfo->err->output_message)) (cinfo);*/  

    /* Create the message */ 
    (*(cinfo->err->format_message)) (cinfo, jpegLastErrorMsg); 

    /* Jump to the setjmp point */ 
    longjmp(myerr->setjmp_buffer, 1); 

} 

А затем зарегистрировать его с помощью jpeg_std_error.

FILE* fileHandler; 
/* ... */ 
struct jpeg_decompress_struct cinfo; 
jpegErrorManager jerr; 
cinfo.err = jpeg_std_error(&jerr.pub); 
jerr.pub.error_exit = jpegErrorExit; 
/* Establish the setjmp return context for my_error_exit to use. */ 
if (setjmp(jerr.setjmp_buffer)) { 
    /* If we get here, the JPEG code has signaled an error. */ 
    cerr << jpegLastErrorMsg << endl; 
    jpeg_destroy_decompress(&cinfo); 
    fclose(fileHandler); 
    return 1; 
} 

Вы можете найти полный пример here.

+0

Спасибо так много, дайте мне попробовать, и я вам скажу :) –

+0

Вау, Я не думал об этих механизмах прыжка. Большое вам спасибо, это сработало! –

+0

Вы можете попробовать C++ lambda с исключениями для создания обработчика исключений inline - см. Мой ответ http://stackoverflow.com/a/34351005/1151329 –

7

Поскольку вопрос был ориентируетесь C++, альтернативный подход, с исключениями:

обработчик ошибок:

void jpegErrorExit (j_common_ptr cinfo) 
{ 
    char jpegLastErrorMsg[JMSG_LENGTH_MAX]; 
    /* Create the message */ 
    (*(cinfo->err->format_message)) (cinfo, jpegLastErrorMsg); 

    /* Jump to the setjmp point */ 
    throw std::runtime_error(jpegLastErrorMsg); // or your preffered exception ... 
} 

Использование:

FILE* fileHandler; 
/* ... */ 
struct jpeg_decompress_struct cinfo; 
struct jpeg_error_mgr jerr; 
cinfo.err = jpeg_std_error(&jerr); 
jerr.error_exit = jpegErrorExit; 
try { 
    jpeg_create_decompress(&cinfo); 
    jpeg_stdio_src(&cinfo, fileHandler); 
    /// ... 
    jpeg_destroy_decompress(&cinfo); 
    fclose(fileHandler); 
} 
catch (std::runtime_exception & e) { 
    jpeg_destroy_decompress(&cinfo); 
    fclose(fileHandler); 
    throw; // or return an error code 
} 
+1

Спасибо за ваш комментарий. Я думаю, что интересно отметить, что C++ не означает, что мы должны использовать исключения. Фактически, стиль кодирования Google C++ гласит: «Мы не используем исключения» и не более :-) –

+2

Я согласен, это не значит, что вы должны, я просто хочу, чтобы вы могли. Кроме того: в основном прыжки могут вызывать те же потенциальные проблемы, что и исключения, обычно не известны программистам на С ++, и даже могут быть еще более опасны: они могут легко испортить ваш RAII. От www.cplusplus.com: «В C++ реализация может выполнять раскрутку стека, которая уничтожает объекты с автоматической продолжительностью. Если это вызывает любые нетривиальные деструкторы, это приводит к неопределенному поведению». И руководство по стилю Google также упоминает, что существуют исключения для всех этих правил, особенно когда используются библиотеки. –

+0

Но libjpeg - это C, а не C++, поэтому у него нет деструкторов, нетривиальных или других, с которыми запутался setjmp/longjmp. –

3

Использование C++ 11 Я реализовал это с помощью лямбда (по аналогии с ответом Марко):

[](j_common_ptr cinfo){throw cinfo->err;} 

который работает хорошо. Только тогда зацепиться 'структура jpeg_error_mgr * ERR'

т.е.

struct jpeg_error_mgr jerr_mgr; 
cinfo.err = jpeg_std_error(&jerr_mgr); 
jerr_mgr.error_exit = [](j_common_ptr cinfo){throw cinfo->err;}; 

и

try 
    { 
     jpeg_create_decompress(&cinfo); 

     ... 
    } 
    catch (struct jpeg_error_mgr *err) 
    { 
     char pszErr[1024]; 
     (cinfo.err->format_message)((j_common_ptr)&cinfo, pszErr); 

     ... 
    }