Error handling with return codes · Обработка ошибок с кодами возврата
C has no try/except
- Some languages throw exceptions when something goes wrong. C does not have exceptions.
- Instead, a C function reports trouble through its return value — a status code.
- The caller checks that code after every call and decides what to do.
В C нет try/except
- Некоторые языки выбрасывают исключения при ошибках. В C нет исключений.
- Вместо этого функция C сообщает о проблемах через свое возвращаемое значение — код статуса.
- Вызывающий код проверяет этот код после каждого вызова и решает, что делать.
Return a status code
- A common rule: return
0for success and a negative number like-1for failure. - So
int do_thing(...)returns0when it worked,-1when it could not. - The real "answer" is then handed back a different way (see the next step).
Возврат кода статуса
- Распространенное правило: возвращать
0для успеха и отрицательное число, например-1, для ошибки. - Так что
int do_thing(...)возвращает0при успехе, а-1при неудаче. - Реальный «ответ» тогда возвращается иным способом (см. следующий шаг).
Reporting the answer through an out-pointer
- If the return value is a status code, where does the real result go? Through an out-pointer.
- The caller passes the address of a variable; the function writes the answer with
*. - On failure, the function returns
-1and simply leaves that variable alone.
Передача ответа через out-pointer (указатель вывода)
- Если возвращаемое значение — код статуса, куда идет реальный результат? Через out-pointer.
- Вызывающий код передает адрес переменной; функция записывает ответ с помощью
*. - При ошибке функция возвращает
-1и просто не трогает эту переменную.
Sentinels for "no value"
- A sentinel is a special value that means "nothing here":
-1for an index,NULLfor a pointer. - Functions use sentinels so the caller can tell success from failure with a simple check.
- Always check for the sentinel before you trust the result.
Сентинели для «нет значения»
- Сентинел — это специальное значение, означающее «ничего здесь»:
-1для индекса,NULLдля указателя. - Функции используют сентинели, чтобы вызывающий код мог отличить успех от неудачи простой проверкой.
- Всегда проверяйте наличие сентинеля, прежде чем доверять результату.
#include <stdio.h>
int safe_div(int a, int b, int *result) {
if (b == 0) return -1; // failure: cannot divide by zero
*result = a / b; // success: hand back the answer
return 0;
}
int main(void) {
int r;
if (safe_div(10, 2, &r) == 0) {
printf("%d\n", r); // 5
}
return 0;
}
Common mistakes
- Return a non-zero code from
mainto signal an error. - Check the return value of any function that can fail.
Распространенные ошибки
- Верните ненулевой код из
mainдля сигнализации об ошибке. - Проверяйте возвращаемое значение любой функции, которая может завершиться неудачей.
Now you try
- Return
0on success and-1on failure, and write the real answer through the out-pointer. - On failure, do not touch the out-pointer. Do not write a
main— the checker provides one.
Теперь попробуйте сами
- Возвращайте
0при успехе и-1при неудаче, а реальный результат записывайте через out-указатель. - При ошибке не трогайте out-указатель. Не записывайте туда
main— это делает проверка.
Complete int safe_div(int a, int b, int *result): if b is 0, return -1 and leave *result alone. Otherwise store a / b in *result and return 0. Do not write a main. · Завершите блок int safe_div(int a, int b, int *result): если значение b равно ⟨0⟩, верните ⟨-1⟩ и оставьте ⟨*result⟩ без изменений. Иначе сохраните ⟨a / b⟩ в ⟨*result⟩ и верните ⟨0⟩. Не пишите код для main.
Click Run to see the output here. · Нажмите Запустить, чтобы увидеть результат здесь.
Complete int parse_int(const char *s, int *out): if s is a valid integer (digits, with an optional leading -), store its value in *out and return 0; otherwise return -1. Do not write a main. · Завершите блок int parse_int(const char *s, int *out): если ⟨s⟩ является допустимым целым числом (цифры, с возможной ведущей знаком ⟨-⟩), сохраните его значение в ⟨*out⟩ и верните ⟨0⟩; иначе верните ⟨-1⟩. Не пишите код для main.
Click Run to see the output here. · Нажмите Запустить, чтобы увидеть результат здесь.
Complete int withdraw(int balance, int amount, int *new_balance): if amount is more than balance, return -1. Otherwise set *new_balance to balance - amount and return 0. Do not write a main. · Заполните int withdraw(int balance, int amount, int *new_balance): если amount больше balance, верните -1. Иначе установите *new_balance в значение balance - amount и верните 0. Не пишите не main.
Click Run to see the output here. · Нажмите Запустить, чтобы увидеть результат здесь.