2013-04-23 7 views
0

ССАГПЗ (GCC) 4.7.2 C89Разрешение сообщений об ошибках пузыриться

Я всегда задавался вопросом, что является лучшей практикой при возвращении сообщения об ошибках от вызываемых функций?

В одном из моих общих библиотек я создаю меня эту функцию:

/* Create directory structure */ 
apr_status_t dir_create(apr_pool_t *mem_pool) 
{ 
#define SRC "test_src" 

    apr_fileperms_t file_perms = 
     APR_FPROT_UWRITE | 
     APR_FPROT_GWRITE | 
     APR_FPROT_WWRITE | 
     APR_FPROT_UREAD | 
     APR_FPROT_GREAD | 
     APR_FPROT_WREAD | 
     APR_FPROT_UEXECUTE | 
     APR_FPROT_GEXECUTE; 

    if(apr_dir_make(SRC, file_perms, mem_pool) != APR_SUCCESS) { 
     LOG_CRIT("Failed to create directory"); 
     return FALSE; 
    } 

    return TRUE; 
} 

LOG_CRIT отобразит соответствующее сообщение об ошибке, связанной с егто.

В моем приложении, который будет вызывать эту функцию у меня есть это:

if(dir_create(mem_pool) != TRUE) { 
    return 1; 
} 
LOG_INFO("Directory has been created"); 

Для примера, когда выше не будет войти, как это:

[CRITICAL] dir_create:28: error [File exists] Failed to create directory 

Я задаюсь я должен поместить сообщение об ошибке в приложении, которое вызывает библиотечную функцию. Или вы всегда должны отображать сообщение об ошибке, как только получите его в кратчайшие сроки?

В приведенном выше примере отображается сообщение об ошибке в вызываемой функции. И когда функция вернется, я просто вернусь 1, чтобы закончить приложение или сделать что-то еще.

Другая мысль, лучше вернуть индикатор ошибки и позволить вызывающей функции отображать источник ошибки?

ответ

2

Некоторые опции, становится все более сумасшедшим - вы, вероятно, есть инстинкт для того, что подойдет вашей ситуации ;-P Это больше, чтобы стимулировать ваше понимание вариантов:

  • захвата столько, сколько вы считаете разумным - __FILE__ , __LINE__, errno, описание ошибки, попытка операции, параметры, результат и т. Д. - на линии, обнаруживающей ошибку
  • принцип: делать только то, что звонящий хочет, чтобы вы сделали; множество подходов с различными компромиссами:
    • возвращают небольшое, легко проверяемое значение данных (число или указатель), но предоставляют некоторые функции доступа, чтобы легко получить другую информацию, захваченную выше, поэтому код, в который вы «возвращаетесь», может делать все, что угодно как ...
      • eg вызывающий может разыменовать этот указатель, чтобы получить деталь ошибки, strerror()-подобные функции, вызывающий вызываемый указатель на сообщение об ошибке печати (если видимость в значении этого сообщения не требуется вызывающим) ...
    • немедленно уведомляет рутину, управляемую вызывающим абонентом, которая может подавлять или перенаправлять ошибку, поскольку вызывающий объект считает нужным; например ваша библиотека может предоставить указатель на функцию, которую вы вызываете, которую вызывающий может перенаправить - по умолчанию может регистрироваться стандартная ошибка или какое-то другое общепринятое действие
    • дизайн вашего кода библиотеки должен быть #include d и использовать препроцессор, предоставляемый вызывающим абонентом макро, предусматривающей обработка ошибки поведение
    • жёстко вывод сообщение об ошибке из вашей библиотеки, но пусть вызывающий изменить поток, к которому, которые могут быть посланы, чтобы они могли подавить его при желании

Вам нужно более серьезно относитесь к подобным вещам, если приложения, использующие вашу библиотеку, похожи на чтобы попытаться выполнить операции спекулятивно (например, отказоустойчивость или транзакционная семантика), особенно если определенные действия с ошибкой имеют необратимые последствия (например, некоторые системы пакетных заданий считают, что задание было неудачным, если что-либо напечатано на stderr), но с точки зрения программы функция библиотеки может не являться сбоем или выскакиванием диалоговое окно с графической ошибкой будет препятствовать автоматической работе).

1

Я бы рекомендовал регистрировать сообщение об ошибке на самом низком уровне, как вы здесь делаете. Это особенно важно, если вам нужно получить доступ к errno, который в противном случае мог бы измениться к моменту получения функции более высокого уровня. На этом уровне я сделаю сообщения об ошибках максимально техничными и конкретными.

Основываясь на возвращаемом значении функций вашей библиотеки, ваш код приложения может принять какое-либо действие (например, он может отображать всплывающее окно, дающее человеко-читаемое описание ошибки, или он может писать до stderr). Обычно это делается на самом высоком уровне - уровень пользовательского интерфейса, если хотите.