Мне нравится ошибка как возвращаемое значение путь. Если Вы разрабатываете API, и Вы хотите использовать свою библиотеку, максимально безболезненную, думают об этих дополнениях:
хранилище все возможные состояния ошибки в одном typedef'ed перечислении и использовании это в Вашем lib. Только возвратите ints или еще хуже, смешайте ints или различные перечисления с кодами возврата.
обеспечивают функцию, которая преобразовывает ошибки во что-то человекочитаемое. Может быть простым. Просто ошибочное перечисление в, символ константы*.
я знаю, что эта идея делает многопоточное использование немного трудным, но было бы хорошо, если прикладной программист может установить глобальный ошибочный обратный вызов. Тем путем они смогут поместить точку останова в обратный вызов во время сессий поиска ошибки.
Hope это помогает.
Второй подход позволяет компилятору произвести больше оптимизированного кода, потому что, когда адрес переменной передается функции, компилятор не может сохранить свое значение в регистре (регистрах) во время последующих вызовов к другим функциям. Код завершения обычно используется только однажды, сразу после вызова, тогда как "реальные" данные, возвращенные из вызова, могут использоваться чаще
EDIT:If Вам нужен доступ только к последней ошибке, и Вы не работаете в многопоточной среде.
можно возвратиться только истинный/ложный (или некоторый #define, если Вы работаете в C и не поддерживаете bool переменные), и имейте глобальный Ошибочный буфер, который будет содержать последнюю ошибку:
int getObjectSize(MYAPIHandle h, int* returnedSize);
MYAPI_ERROR LastError;
MYAPI_ERROR* getLastError() {return LastError;};
#define FUNC_SUCCESS 1
#define FUNC_FAIL 0
if(getObjectSize(h, &size) != FUNC_SUCCESS ) {
MYAPI_ERROR* error = getLastError();
// error handling
}
В дополнение к тому, что было сказано до возврата Вашего кода ошибки, исчерпывают утверждение или подобную диагностику, когда ошибка возвращается, поскольку это сделает трассировку намного легче. Путем я делаю это должно иметь специализированное, утверждают, что все еще компилируется в при выпуске, но только запущен, когда программное обеспечение находится в режиме диагностики с опцией тихо сообщить файлу журнала или паузе на экране.
я лично возвращаю коды ошибок как отрицательные целые числа с no_error как нуль, но он действительно оставляет Вас с возможной следующей ошибкой
if (MyFunc())
DoSomething();
, альтернатива, возвратили отказ всегда как нуль и используют LastError () функция для предоставления подробной информации фактической ошибки.
Первый подход лучше, по моему скромному мнению:
Я сделал много C, программирующих в прошлом. И я действительно ценил возвращаемое значение кода ошибки. Но, имеет несколько возможных ловушек:
Я определенно предпочитаю первое решение:
int size;
if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
// Error handling
}
я немного изменил бы его, к:
int size;
MYAPIError rc;
rc = getObjectSize(h, &size)
if ( rc != MYAPI_SUCCESS) {
// Error handling
}
В дополнительном я никогда не буду смешивать законное возвращаемое значение с ошибкой, даже если в настоящее время объем функции, разрешающей Вам сделать так, Вы никогда не будете знать, какой путь реализация функции войдет в будущее.
И если бы мы уже говорящий об обработке ошибок я предложил бы goto Error;
как код обработки ошибок, если приблизительно undo
функция нельзя назвать для обработки обработки ошибок правильно.
Я лично предпочитаю бывший подход (возвращающий индикатор ошибки).
, Где необходимый результат возврата должен просто указать, что ошибка произошла, при этом другая функция использовалась узнать точную ошибку.
В Вашем getSize () пример я полагал бы, что размеры должны всегда быть нулем или положительный, настолько возвращающийся отрицательный результат может указать, что ошибка, во многом как системные вызовы UNIX делают.
я не могу думать ни о какой библиотеке, которой я пользовался, который идет для последнего подхода с ошибочным объектом, переданным в как указатель. stdio
, и т.д. все идут с возвращаемым значением.
Подход UNIX является самым подобным Вашему второму предложению. Возвратите или результат или сингл, "он пошел неправильно" значение. Например, открытый возвратит дескриптор файла на успехе или-1 при отказе. При отказе это также устанавливает errno
, внешнее глобальное целое число для указания , который произошел отказ.
Если это имеет значение, Какао также принимало аналогичный подход. Много методов возвращают BOOL и берут NSError **
параметр, так, чтобы при отказе они установили ошибку и возвратились НЕТ. Затем обработка ошибок похожа:
NSError *error = nil;
if ([myThing doThingError: &error] == NO)
{
// error handling
}
, который является где-нибудь между Вашими двумя опциями :-).
Я использовал оба подхода, и они оба хорошо работали для меня. Какой бы ни один я использую, я всегда пытаюсь применить этот принцип:
, Если единственные возможные ошибки являются ошибками программиста, не возвращайте код ошибки, утверждает использование в функции.
утверждение, которое проверяет исходные данные ясно, передает то, что ожидает функция, в то время как слишком много проверки ошибок может затенить логику программы. Решение, что сделать для всех различных ошибочных случаев, может действительно усложнить дизайн. Почему фигура, как functionX должен обработать нулевого указателя, если можно вместо этого настоять, чтобы программист никогда не передавал тот?
Я использую первый подход каждый раз, когда я создаю библиотеку. Существует несколько преимуществ использования typedef'ed перечисления как код возврата.
, Если функция возвращает более сложный вывод, такой как массив и это - длина, которую Вы не должны создавать произвольные структуры для возврата.
rc = func(..., int **return_array, size_t *array_length);
Это допускает простую, стандартизированную обработку ошибок.
if ((rc = func(...)) != API_SUCCESS) {
/* Error Handling */
}
Это допускает простую обработку ошибок в библиотечной функции.
/* Check for valid arguments */
if (NULL == return_array || NULL == array_length)
return API_INVALID_ARGS;
Используя typedef'ed перечисление также позволяет, чтобы перечислимое имя было видимо в отладчике. Это допускает более легкую отладку без потребности постоянно консультироваться с заголовочным файлом. Наличие функции для перевода этого перечисления в строку полезно также.
самая важная проблема независимо от используемого подхода должна быть последовательной. Это применяется к функции и именованию аргумента, упорядочиванию аргумента и обработке ошибок.