2010-10-06 2 views
7

Безопасно ли вызывать errno несколько раз при работе с той же ошибкой. Или безопаснее работать с локальной копией?Следует избегать последовательных вызовов `errno`?

Этот пример иллюстрирует мой вопрос:

// If recvfrom() fails it returns -1 and sets errno to indicate the error. 
int res = recvfrom(...); 
if (res < 0) 
{ 
    // Risky? 
    printf("Error code: %d. Error message: %s\n", errno, strerror(errno)); 

    // Safer alternative? 
    int errorNumber = errno; 
    printf("Error code: %d. Error message: %s\n", errorNumber, strerror(errorNumber)); 
} 
+1

+1 интересный вопрос, который, как оказалось, имеет нетривиальный ответ и возможные практические последствия. –

ответ

5

Значение егто должно быть определено только после вызова функции, для которой он явно заявлены быть установлены и пока она изменяется следующим или если приложение присваивает ему значение.

http://www.opengroup.org/onlinepubs/009695399/functions/errno.html

Однако даже strerror теоретически может рассчитывать как вызов функции, которая может изменить его (см комментарий по Schot), так что вы должны, теоретически, по-прежнему идти с копи-первой формы.

+1

Однако printf может вызвать изменение errno. Страница руководства в http://linux.die.net/man/3/errno (я полагаю, что это из Linux) предостерегает от использования этого в printf. Однако это не проблема для вашей конкретной ситуации - компилятор будет оценивать 'errno' и' strerror (errno) 'как перед вызовом printf. – Habbie

+1

Но вызов 'strerror' может изменить' errno'. Хотя я не думаю, что есть какая-то реализация глупо/зла, чтобы сделать это. (За исключением, возможно, DeathStation 9000). – schot

+0

Верно, и компилятор может решить оценить strerror (errno) перед оценкой errno. Я обновляю свой ответ. – Habbie

1

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

+1

'errno' не является переменной. –

2

любой стандартной библиотечной функции, включая Printf и strerror разрешено изменять ERRNO, даже если происходит на самом деле нет ошибки:

7,5 3 Значение егто равно нулю при запуске программы, но никогда не установлен нуль любой библиотечной функцией. 170) Значение егто может быть установлено в ненулевых при вызове функции библиотеки ли не существует ошибка, при условии использования егта не документированы в описании функции в настоящем стандарте.

+1

Связанный с Tangential: можете ли вы найти какой-либо язык в стандарте, который запретил бы 'strtol' и family устанавливать' errno' в 'ERANGE', если на самом деле не произошло переполнение? Стандартная процедура заключается в том, чтобы установить 'errno' в 0 перед вызовом этих функций и проверить' errno', если возвращаются 'LONG_MIN' или' LONG_MAX', но если они могут установить 'errno' в' ERANGE' без всякой причины, это стандартный тест кажется недействительным ... –

+0

@R ..: Если использование errno определено для конкретной функции, то никакое другое поведение, кроме явно указанного там, не разрешено в 7.5: «если использование errno не описано в описании функции ". – Secure

+0

Ничего себе это было прямо в вашей цитате, и я пропустил это ... –

1

Вообще в наше время errno нечто гораздо более сложное, чем переменной:

... ERRNO, которая расширяется до модифицируемых Lvalue, который имеет тип INT, значение которого устанавливается в положительный номер ошибки несколькими функциями . Не указано , является ли errno макросом или идентификатором , объявленным с внешней связью . Если определение макроса подавлено для доступа к фактическому объекту , или программа определяет идентификатор с именем errno, поведение не определено.

E.g. в POSIX гарантированно оценивается то, что характерно для текущего потока. Таким образом, он может иметь стоимость доступа, которая выше, чем для простой переменной.

Так что да, я бы пошел на местную копию, если производительность вызывает беспокойство, хотя я никогда не скакал это по-настоящему.

0

Я просто изучал это сам, и я думаю, что другая функция может быть лучше подходит для этой проблемы, perror.PError довольно просто, если вы таНос некоторую память, и вы хотите, то значимое сообщение об ошибке strerror обеспечивает, если таНос не удается:

char **str_array = (char**) malloc(SOME_CONSTANT * sizeof(char*)); 
if (str_array == NULL){ 
    perror("malloc failed on str_array"); 
} 

PError печатает строку, вы набрали, добавляет пространство, то точка с запятой, а затем печатает текст, читаемый человеком. У этого также, похоже, нет побочного эффекта, который делает страус, если я не интерпретирую справочную страницу неправильно, потому что у нее нет раздела для ОШИБКИ: http://man7.org/linux/man-pages/man3/perror.3.html.

Я также делаю последовательные вызовы, которые могут потерпеть неудачу, и perror выглядит как меньше строк кода и лучшего синтаксиса. Тем не менее, я новичок в C, поэтому, пожалуйста, отредактируйте или удалите, если эта информация неточна.

Смежные вопросы