LINUX.ORG.RU

[C] Обработка ошибок

 


0

0

Подскажите какую-нибудь литературу про обработку ошибок в C. Интересуют больше не технические аспекты, а вопросы правильности и разумности.

В частности интересует следующее:

1. Правильно ли сообщать информацию об ошибках через errno или стоит свой аналог такой переменной завести? Что делать если хочется положить в errno код ошибки отличный от стандартного?

2. Как вообще определить, что при выполнении математической операции возникла ошибка ERANGE?

3. Где в коде следует выводить сообщения об ошибках? Как я понимаю, в библиотеке не должно вообще ничего выводиться, всё только через возвращаемые значения и errno. А вот в программе следует выводить сообщение об ошибке сразу там где она возникла, или стоит стараться отделять рабочие функции и функции общающиеся с пользователем?

★★★

> 1. Правильно ли сообщать информацию об ошибках через errno или стоит свой аналог такой переменной завести? Что делать если хочется положить в errno код ошибки отличный от стандартного?

Если все твои ошибки изначально приходят только из сисвызовов, то можно юзать errno. Обычно даже ничего делать не придётся дополнительно, просто оставлять errno нетронутым после обломившегося вызова. В общем случае лучше заводить своё множество ошибок и возвращать их не через errno, а напрямую (a-la pthread_kill()). Можно завести одну специальную ошибку: «системная ошибка, подробности в errno».

3. Где в коде следует выводить сообщения об ошибках? Как я понимаю, в библиотеке не должно вообще ничего выводиться, всё только через возвращаемые значения и errno.

Я думаю, это правильно. Но можно, например, предусмотреть возможность настройки библиотеки. Например, можно передавать в библиотеку FILE*, куда писать логи, или ссылку на какой-нибудь более высокоуровневый «логгер».

const86 ★★★★★
()
Ответ на: комментарий от const86

Если все твои ошибки изначально приходят только из сисвызовов, то можно юзать errno. Обычно даже ничего делать не придётся дополнительно, просто оставлять errno нетронутым после обломившегося вызова.

Это плохая практика, см. man errno в разделе NOTES. Я поэтому сразу сохраняю errno в отдельную переменную(int saved_errno) с которой уже работаю.

true_admin ★★★★★
()
Ответ на: комментарий от const86

Я писал макросы TRY CATCH THROW (на setjump longjump) и пользовался «лёгкими» исключениями

theos ★★★
()

Ошибки не нужны. А на случай непредвиденных ситуаций (ошибка выделения памяти и т.д.) есть assert.

melkor217 ★★★★★
()
Ответ на: комментарий от anonymous

> смотри как сделана система обработки ошибок в glib:

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

GArik ★★★
() автор топика
Ответ на: комментарий от const86

Какой вариант лучше?

1.

double kinematic(double t0, double l, double v)
/// функция вычислият время прихода волны согласно скорости и удалению
{
	if(t < 0.)
	{
		fprintf(stderr, "\nwarning: time is negative: %f\n", t0);
		return NAN;
	}
	if(v < 0.)
	{	
		fprintf(stderr, "\nwarning: velocity is negative: %f\n", v);
		return NAN;
	}
	else if(v == 0.)
	{
		if(l == 0.)
			return t0;
		
		return INFINITY;
	}
	else // l может быть отрицательным (из практических соображений)
		return sqrt(t0 * t0 + l * l / (v * v));
}

2.

double kinematic(double t0, double l, double v)
/// функция вычислият время прихода волны согласно скорости и удалению
{
	if(t < 0.)
	{	
		errno = EDOM;
		return NAN;
	}
	if(v < 0.)
	{	
		errno = EDOM;
		return NAN;
	}
	else if(v == 0.)
	{
		if(l == 0.)
			return t0;
		
		return INFINITY;
	}
	else // l может быть отрицательным (из практических соображений)
		return sqrt(t0 * t0 + l * l / (v * v));
}

Как всё таки вообще проверить операции на ERANGE? Не здесь а вообще.

GArik ★★★
() автор топика
Ответ на: комментарий от GArik

Какой вариант лучше?

Первый мусорит в stderr, но при этом не даёт возможности вызывающей функции увидеть причину ошибки. Второй юзает системные номера ошибок для своих ошибок, да ещё и _пишет_ их в errno. Итого 2:2, боевая ничья.

Как всё таки вообще проверить операции на ERANGE?

man log гласит: «If the integer expression (math_errhandling & MATH_ERRNO) is non-zero, then errno shall be set to [ERANGE]. If the integer expression (math_errhandling & MATH_ERREXCEPT) is non-zero, then the divide-by-zero floating-point exception shall be raised.» Получается примерно так:

if (!(math_errhandling & MATH_ERRNO))
    exit(1); // Ошибки не ловятся
if (math_errhandling & MATH_ERREXCEPT)
    sighold(SIGFPE); // Не отвлекаться на сигналы

Если хочется ловить сигнал, а не errno, то делаем наоборот.

const86 ★★★★★
()
Ответ на: комментарий от const86

Я ничего не понял.

юзает системные номера ошибок для своих ошибок, да ещё и _пишет_ их в errno

А зачем выдумывать свои обозначения для ошибок если есть стандартные? Зачем писать отчёт об ошибке в свою переменную если есть стандартная?

man log гласит

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

P.S. Так что-то ни одной ссылки на статью я и не получил =(

GArik ★★★
() автор топика
Ответ на: комментарий от anonymous

В релизной сборке средств отладки не должно быть. Пусть падает.

melkor217 ★★★★★
()
Ответ на: комментарий от GArik

А зачем выдумывать свои обозначения для ошибок если есть стандартные? Зачем писать отчёт об ошибке в свою переменную если есть стандартная?

Если устраивает, что в обоих случаях в примере получается один и тот же EDOM, то пусть будет. А стандартная переменная errno придумана для системных функций, нечего в ней грязными руками ковыряться.

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

errno = 0;
double x = log(a + b + c);
if (errno == ERANGE)
    die("ой");

Можно вместо этого поставить обработчик сигнала, но я не думаю, что так будет проще.

const86 ★★★★★
()
Ответ на: комментарий от GArik

> Зачем писать отчёт об ошибке в свою переменную если есть стандартная?

затем, что errno может быть макросом. посмотри на errno.h и bits/errno.h

ananas ★★★★★
()
Ответ на: комментарий от ananas

>> Зачем писать отчёт об ошибке в свою переменную если есть стандартная?

затем, что errno может быть макросом. посмотри на errno.h и bits/errno.h

Это не страшно: «The _lvalue_ errno is used by many functions to return error values. The value of errno shall be defined only after a call to a function for which it is explicitly stated to be set and until it is changed by the next function call or if _the application assigns_ it a value.»

const86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.