А теперь что-то совершенно другое ...
Другой подход заключается в использовании структуры для хранения информации об ошибках, например:
struct ErrorInfo
{
int errorCode;
char *errorMessage;
#if DEBUG
char *functionName;
int lineNumber;
#endif
}
Лучший способ использовать это - вернуть результаты вашего метода в качестве кода возврата (например, «FALSE for fail», или «указатель файла или NULL в случае сбоя», «размер буфера или 0 в случае сбоя»). "и т. д.) и передайте ErrorInfo в качестве параметра, который будет вызывать вызываемая функция в случае сбоя.
Это дает подробные отчеты об ошибках: если метод завершается ошибкой, вы можете ввести более простой код ошибки (например, сообщение об ошибке, строку кода и файл ошибки или что-то еще). Хорошая вещь в том, что структура - это то, что если вы думаете о чем-то, что-нибудь полезное позже, вы можете просто добавить это - например, в моей структуре выше я позволил отладочной сборке включить местоположение ошибки ( файл / строка), но вы можете в любой момент добавить туда дамп всего стека вызовов, не изменяя код клиента.
Вы можете использовать глобальную функцию для заполнения ErrorInfo, чтобы можно было аккуратно управлять возвратом ошибки, и вы можете обновить структуру, чтобы легко предоставлять больше информации:
if (error)
{
Error(pErrorInfo, 123, "It failed");
return(FALSE);
}
... и у вас могут быть варианты этой функции, которые возвращают FALSE, 0 или NULL, чтобы позволить большинству возвратов ошибок быть выраженными в одной строке:
if (error)
return(ErrorNull(pErrorInfo, 123, "It failed"));
Это дает вам множество преимуществ класса Exception на других языках (хотя вызывающему все еще нужно обрабатывать ошибки - вызывающие должны проверять коды ошибок и, возможно, должны вернуться рано, но они ничего не могут сделать или затем - в ничто и позволяют ошибке распространяться по цепочке вызывающих методов до тех пор, пока один из них не захочет ее обработать, как исключение.
Кроме того, вы можете пойти дальше, чтобы создать цепочку отчетов об ошибках (например, «InnerException»):
struct ErrorInfo
{
int errorCode;
char *errorMessage;
...
ErrorInfo *pInnerError; // Pointer to previous error that may have led to this one
}
Затем, если вы «поймаете» ошибку из вызываемой функции, вы можете создать новое описание ошибки более высокого уровня и вернуть цепочку этих ошибок. например «Скорость мыши вернется к значению по умолчанию» (потому что) «Блок настроек« MousePrefs »не может быть найден» (потому что) «Ошибка чтения XML» (потому что) «Файл не найден».
* * 1 022 * т.е. 1023 *
FILE *OpenFile(char *filename, ErrorInfo *pErrorInfo)
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
return(ChainedErrorNull(pErrorInfo, "Couldn't open file"));
return(fp);
}
XmlElement *ReadPreferenceXml(ErrorInfo *pErrorInfo)
{
if (OpenFile("prefs.xml", pErrorInfo) == NULL)
return(ChainedErrorNull(pErrorInfo, "Couldn't read pref"));
...
}
char *ReadPreference(char *prefName, ErrorInfo *pErrorInfo)
{
XmlElement *pXml = ReadPreferenceXml(pErrorInfo);
if (pXml == NULL)
return(ChainedErrorNull(pErrorInfo, "Couldn't read pref"));
...
}