Стандартные функции C: проверка на -1 или 0? - PullRequest
5 голосов
/ 01 октября 2010

Многие стандартные функции C и POSIX возвращают -1 для ошибки и 0 в случае успеха, например truncate, fflush, msync и т. Д.

int ret = truncate("/some/file", 42);

Лучше ли проверять успешность с ret != -1 или ret == 0 и почему?

Мои мысли

По моему опыту, большинство людей проверяют наличие ошибки (ret != -1), так как обычно она только одна (рассмотрим функции, которые возвращают NULL или EOF при ошибке). Однако, оглядываясь назад, можно было бы увидеть, что эти функции могли бы выиграть от непосредственного возврата errno (где 0 не считается ошибкой).

Существует также беспокойство, что функция возвращает что-то отличное от 0 или -1, или что дополнительные возвращаемые значения добавляются позже. В этих сценариях имеет смысл проверить на «самый узкий» диапазон значений, указывающих на успех (ret == 0).

Update0

Я полагаю, что люди знают, что EOF обычно определяется как -1.

Ответы [ 9 ]

8 голосов
/ 01 октября 2010

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

POSIX, с другой стороны, более последовательный. Почти все функции POSIX определены как возвращающие -1 с более конкретным кодом ошибки, доступным в errno. Некоторые функции просто возвращают 0 для успеха, в то время как другие имеют множество значений успеха. Например, open() возвращает дескрипторы файлов, read() возвращает количество прочитанных байтов и т. Д.

Для согласованности мне нравится всегда использовать один и тот же тест при вызове функций POSIX: не проверять на успешность, проверять на неудачу. Функции POSIX, которые сегодня возвращают -1 при ошибке, всегда будут возвращать ровно -1, поэтому я бы использовал одну из двух проверок для всех них:

if (ret == -1) {
    perror(...);
}

// or

if (ret < 0) {
    perror(...);
}

(я предпочитаю первый, но второй, более общий, меня не беспокоит.)

3 голосов
/ 01 октября 2010

На мой взгляд, это действительно зависит от того, что вам нужно сделать, и диапазона возвращаемых значений.

Принять вызов с одним значением успеха и многими значениями отказа.Как правило, == или != проще сопоставить с успешным возвращаемым значением, чем сверять с любыми ошибочными значениями.В этом случае вы должны протестировать против != success, если вам нужно, скажем, зарегистрировать и вернуть или выбросить в случае сбоя.

При вызове с одним и одним требуемое поведение более важно,поэтому я предлагаю выбрать более читаемый.Если ваши коды должны реагировать и, возможно, возвращаться в случае сбоя, проверьте == failure вместо != success.Первый более читабелен, поскольку требует одного шага мышления, а константа сбоя может быть кратко названа.

Возможно, вы также захотите рассмотреть, какой из них более вероятен, и обрабатывать его первым, или который численно больше или меньше.

В вашем случае, когда две функции совместно используют код успеха, а с разными кодами сбоя он падает до того значения, которое кажется более читабельным.Я бы согласился с тем, что тестирование == 0 в обоих случаях показалось бы лучше, но это действительно зависит от того, сколько кода находится между вызовами.Если у вас несколько десятков строк, разница в удобочитаемости может быть незначительной.Если это очень близко, вы можете даже ИЛИ получить результаты вместе и сэкономить себе еще несколько шагов.

3 голосов
/ 01 октября 2010

Сравнивая справочные страницы для truncate и fflush, оба возвращают 0 в случае успеха, но возвращают разные значения для ошибки (усечение -> -1, fflush -> EOF). Так что я бы проверил на 0.

2 голосов
/ 01 октября 2010

Что бы вы ни делали, никогда не делайте ярлык теста на успех с

if (!ret) 

Это сбивает с толку, и кто-то (включая вас) будет ошибочно читать его позже как тест на неудачу Обычно лучше использовать явные тесты.

2 голосов
/ 01 октября 2010

Всегда проверяйте man-страницы на наличие кодов возврата.

Обычно 0 означает успех, но существуют исключения, такие как printf().

Проверка man 2 intro на наличие ошибок и кодов ошибок системных вызовов.

2 голосов
/ 01 октября 2010

Рекомендации по сертификации , похоже, предпочитают проверку "! = 0", как это допустимо во многих их примерах кода.

1 голос
/ 01 октября 2010

Для большинства функций API POSIX отрицательные значения являются ошибками.Так что я бы проверил на неудачу с if (ret < 0).

1 голос
/ 01 октября 2010

Если определение таково, что 0 означает успех, и вы хотите проверить на успех , тогда вы должны проверить эквивалентность на 0. (И это ни по какой другой причине, кроме читабельности при сдвиге)

0 голосов
/ 01 октября 2010

Мое эмпирическое правило заключается в том, что подобные функции возвращают код ошибки (или только то, произошла ли ошибка) через возвращаемое значение. Таким образом, для меня имеет смысл, что возвращаемое значение 0 означает, что не было ничего такого, что можно было бы вернуть, и что никакой ошибки не произошло. Поэтому я просто проверяю, было ли возвращаемое значение 0, если я хочу проверить, была ли функция успешной, а если нет, то просто проверяю, что было значением ошибки, и соответственно с ним работаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...