#c #api #errno
#c #API #errno
Вопрос:
Рекомендуете ли вы использовать errno в новых C API?
Должны ли другие методы сообщать о проблемах, таких какhttp://developer.gnome.org/glib/stable/glib-Error-Reporting.html использовать вместо этого?
Что вы рекомендуете?
Ответ №1:
errno
должно быть зарезервировано для стандартной библиотеки C, программа должна рассматривать его как значение, доступное только для чтения.
При написании нового кода я настоятельно не рекомендую использовать глобальную переменную в стиле errno для проверки кода ошибки. Допустим, у вас есть функции, a
через b
которые ab_error
сообщают об их состоянии, тогда вы должны написать что-то вроде этого:
a();
if( ab_error == AB_NOERROR ) {
b();
if( ab_error == NO_ERROR ) {
/* ... */
}
}
Вы видите, что вы довольно быстро наращиваете уровни вложенности. Однако, если ваши функции вернули код ошибки, вы можете записать его следующим образом:
int error_a;
int error_b;
if( (error_a = a()) == A_NOERROR
amp;amp; (error_b = b()) == B_NOERROR
){
/* ... */
} else {
/* test the error variables */
}
вы даже можете связать несколько состояний ошибки, подобных этому:
int error_a;
int error_b;
int error_c;
if( (error_a = a()) == A_NOERROR
amp;amp; ( (error_b = b()) == B_NOERROR
|| (error_c = c()) == C_NOERROR )
){
/* ... */
} else {
/* test the error variables */
}
Который намного более удобочитаем, чем если бы вы разбили все это на несколько вложенных операторов if.
Комментарии:
1. errno не следует рассматривать как доступный только для чтения. В библиотеке c есть определенные функции (например, strtol, strtod), для которых ошибки могут быть обнаружены, только если вызывающий очистит errno перед вызовом.
2. @William: Конечно, но что я имел в виду: не используйте его для передачи ваших собственных кодов ошибок.
Ответ №2:
Вы всегда можете спросить себя, насколько хорошо глобальная errno
работает в программах с несколькими потоками (или другими формами параллелизма, не содержащими отдельных копий глобальных переменных). Типичный вывод, вероятно, будет «не очень хорошо», и, следовательно, другие решения могут быть предпочтительнее.
Комментарии:
1. Это не «глобальный
errno
«, это » глобальныйerrno
«, и он определяется не какextern int
, а как макрос, который расширяется до значения типаint
, именно потому, что он должен быть специфичным для потока.2. @R.: Спасибо за комментарий, вы правы. Мое утверждение было основано на опыте работы на явно несоответствующих платформах, где не всегда соблюдалось требуемое поведение
errno
.3. 1, поскольку, однако, это подчеркивает вредоносность «глобальных переменных», хотя errno не совсем глобальная переменная; однако, my
man errno
говорит «errno может быть макросом. errno является потоковым локальным «, не то чтобы это наверняка был макрос.