Обоснование возврата 0 в качестве значения по умолчанию в C / C ++ - PullRequest
15 голосов
/ 01 декабря 2008

Есть ли причина, по которой ноль используется в качестве возвращаемого значения функции «по умолчанию»? Я заметил, что некоторые функции из stdlib и почти везде, когда не возвращают правильное число (например, pow (), strcpy ()) или ошибку (отрицательные числа), просто возвращают ноль.

Мне просто стало любопытно увидеть несколько тестов, выполненных с отрицательной логикой. Очень запутанно.

Почему бы не вернуть 1, или 0xff, или любое положительное число по этому вопросу?

Ответы [ 13 ]

24 голосов
/ 01 декабря 2008

Обоснование состоит в том, что вы хотите отличить набор всех возможных (отрицательных) возвращаемых значений, соответствующих различным ошибкам от единственной ситуации, в которой все прошло нормально. Самый простой, краткий и самый понятный способ добиться такого различия - это логический тест, и, поскольку в C все целые числа являются «истиной», кроме нуля, вы хотите вернуть ноль, чтобы обозначить «единственную ситуацию», т.е. ноль как «хорошее» значение.

Та же самая аргументация применима к возвращаемым значениям программ Unix, но действительно в тестах в сценариях оболочки Unix логика инвертирована: возвращаемое значение 0 означает «истина» (например, посмотрите на возвращаемое значение /bin/true).

19 голосов
/ 01 декабря 2008

Изначально у C не было «пустоты». Если функция ничего не возвращала, вы просто оставили тип возврата в объявлении пустым. Но это означало, что он вернул int.

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

// Perfectly good K&R C code.
NoReturn()
{
   // do stuff;
   return;
}

int unknownValue = NoReturn();

Люди начали обнулять это, чтобы избежать проблем.

4 голосов
/ 01 декабря 2008

Другая (незначительная) причина связана со скоростью на уровне машины и размером кода.

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

Другими словами, если последняя машинная операция (например, PUSH) привела нас к нулю, все, что нам нужно, это переход на ноль или переход на ноль.

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

4 голосов
/ 01 декабря 2008

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

Может также случиться так, что они ничего не возвращают, что интерпретируется как 0. (По сути, та же концепция.)

2 голосов
/ 01 декабря 2008

Поскольку Bash и большинство других сред оболочки UNIX рассматривают 0 как успех, -x как системную ошибку и x как ошибку, определенную пользователем.

1 голос
/ 01 декабря 2008

Обычно код возврата 0 указывает, что ваша программа закончилась нормально и все в порядке. (Вы можете помнить это как «ноль ошибок», хотя по техническим причинам вы не можете использовать количество ошибок, обнаруженных вашей программой, в качестве кода возврата. См. Стиль.) Код возврата, отличный от 0, указывает, что произошла какая-то ошибка. Если ваш код завершает работу при обнаружении ошибки, используйте выход и укажите ненулевой код возврата. Источник

1 голос
/ 01 декабря 2008

Насколько я понимаю, это было связано с поведением системных вызовов.

Рассмотрим системный вызов open(); если он успешен, он возвращает неотрицательное целое число, которое является дескриптором файла, который был создан. Однако на уровне ассемблера (где есть специальная, не-C-инструкция, которая попадает в ядро), когда возвращается ошибка, она возвращается как отрицательное значение. Когда он обнаруживает возврат ошибки, оболочка кода C вокруг системного вызова сохраняет отрицательное значение в errno (поэтому errno имеет положительное значение), а функция возвращает -1.

Для некоторых других системных вызовов отрицательный код возврата на уровне ассемблера все еще отрицается и помещается в errno, и возвращается -1. Однако эти системные вызовы не имеют специального значения для возврата, поэтому для индикации успеха был выбран ноль. Ясно, что существует большое разнообразие системных вызовов, но большинству удается соответствовать этим соглашениям. Например, stat() и его родственники возвращают структуру, но указатель на эту структуру передается в качестве входного параметра, а возвращаемое значение имеет статус 0 или -1. Даже signal() управляет этим; -1 было SIG_DFL и 0 было SIG_IGN, а другие значения были указателями на функции. Есть несколько системных вызовов без возврата ошибки - getpid(), getuid() и т. Д.

Этот механизм с нулевым показателем успеха затем эмулировался другими функциями, которые на самом деле не были системными вызовами.

1 голос
/ 01 декабря 2008

Я могу ошибаться, но думаю, что это в основном по историческим причинам (истерический изюм?). Я считаю, что в K & R C (до ANSI) не было типа void, поэтому логичным способом написать функцию, которая не выдала ничего интересного, было бы вернуть 0.

Конечно, кто-то здесь исправит меня, если я ошибаюсь ...:)

1 голос
/ 01 декабря 2008

Вероятно, есть куча забытой истории, восходящей к тем временам, когда все было написано в asm. В целом, проверка на ноль намного проще, чем на другие конкретные значения.

0 голосов
/ 11 апреля 2013

Этот аргумент разваливается на части так как: BOOL isTrue = TRUE; или же логическое значение isTrue = true; isTrue = 1 Все, кроме 1, считается ЛОЖНЫМ (включая 0).

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