Соглашения о кодировании для возвратов методов в C ++ - PullRequest
4 голосов
/ 22 сентября 2010

Я заметил, что общее соглашение о кодировании для успешного завершения предполагаемой функциональности метода равно 0. (Как в exit (0)).

Этот вид сбивает меня с толку, потому что, если у меня есть метод вОператор my if и метод возвращают 0, если условие «if» ложно, и, таким образом, заставляет меня на минуту подумать, что метод не удался.Конечно, я знаю, что я должен добавить с "!"(Как в случае (! Method ())), но разве это соглашение не противоречит самому себе?

Ответы [ 8 ]

15 голосов
/ 22 сентября 2010

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

Когда речь идет о кодах ошибок, идея такова: есть только один способ добиться успеха, но есть многоспособы потерпеть неудачу.Возьмите 0 в качестве хорошего единственного уникального числа, представляющего успех, тогда у вас есть любой другой номер, указывающий на неудачу.(Это не имеет никакого смысла.)

Когда дело доходит до флагов ошибок, идея проста: True означает, что это сработало, false означает, что это не так.Обычно вы можете получить код ошибки другими способами и действовать соответствующим образом.

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

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

3 голосов
/ 22 сентября 2010

Соглашение не противоречит само себе, оно противоречит желаемому использованию функции.

Один из них должен измениться, и это не будет конвенцией; -)

Я обычно писал бы либо:

if (Function() == 0) {
    // code for success
} else {
    // code for failure
}

или if (Function() != 0) с чехлами наоборот.

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

int error = Function();
if (!error) {
    // code for success
} else {
    // code for failure, perhaps using error value
}
0 голосов
/ 05 февраля 2014

Я использую это соглашение в моем коде:

int r = Count();

if(r >= 0) {
   // Function successful, r contains a useful non-negative value
}
else {
   // A negative r represents an error code
}

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

Перед использованием исключений примите во внимание проблемы производительности и памяти, которые они вызывают.

0 голосов
/ 23 сентября 2010

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

И в такой ситуации мне совершенно не нравится видеть выражение типа if(!Method()) который на самом деле является тестом на успех.Я также обнаружил, что это может вызвать момент, когда я задаюсь вопросом: проверяет ли это утверждение на успех или провал.По моему мнению, поскольку это не простое логическое возвращение, его не следует писать как единое целое.

В идеале, поскольку возвращение используется в качестве кода ошибки, автор этой функции должен был предоставить перечисление (или, по крайней мере, набор определений), которые можно использовать вместо необработанных чисел.Если так, то я бы всегда предпочел переписать тест как что-то вроде if(Method() == METHOD_SUCCESS).Если автор этого не предоставил, но у вас есть документация по значениям кода ошибки, рассмотрите возможность создания собственного перечисления или определения и использования этого.

Если ничего другого, я бы написал это как if(Method() == 0), потому что тогдапо крайней мере, читателю должно быть ясно, что метод не возвращает простое логическое значение и что ноль имеет особое значение.


Хотя это соглашение часто используется, оно, конечно, не единственноеодин.Я видел соглашения, которые отличают успех и неудачу, используя положительные и отрицательные значения.Это, в частности, происходит, когда функция возвращает счетчик при успешном завершении, но должен возвращать что-то, что не соответствует значению при сбое (часто -1).Я также видел варианты с использованием чисел без знака, где (unsigned int)-1 (он же 0xffffffff) представлял ошибку.И, возможно, есть другие, о которых я даже не могу придумать.

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

И, конечно,все это без упоминания того, что исключения предлагают (среди прочего) совершенно другой способ предоставления информации, когда функция имеет ошибку.

0 голосов
/ 22 сентября 2010
int retCode = SaveWork();

if(retCode == 0) {
  //Success !
} else if(retCode == ERR_PERMISSIONS) {
  //User doesn't have permissions, inform him
  //and let him chose another place
} else if(retCode == ERR_NO_SPACE) {
  //No space left to save the work. Figure out something.
} else {
    //I give up, user is screwd.
}

Таким образом, если 0 / false было возвращено для обозначения ошибки, вы не могли бы определить причину ошибки.Для C ++ вы можете использовать исключения, чтобы различать разные ошибки.Вы также можете использовать глобальную переменную, похожую на errno, которую вы проверяете в случае сбоя.Если не требуются ни исключения, ни глобальные переменные, обычно используется возврат кода ошибки.

0 голосов
/ 22 сентября 2010

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

Как вы говорите, многие функции возвращают 0 для успеха, но они в основном "устаревшие" функции взаимодействия с ОС библиотеки C и следуют стилю взаимодействияиз операционной системы, в которой C был впервые разработан и развернут.

В C ++ 0 может быть значением успеха при переносе такого унаследованного интерфейса C.Другая ситуация, когда вы можете рассмотреть возможность использования 0 для успеха, это когда вы эффективно возвращаете код ошибки, так что все ошибки являются ненулевыми значениями, а 0 имеет смысл как значение, не являющееся ошибкой.Итак, не думайте о возвращаемом значении как о логическом значении (даже если C ++ неявно преобразует его в единицу), но как код ошибки, где 0 означает «нет ошибки».(На практике, как правило, лучше использовать enum).

Тем не менее, вы, как правило, должны возвращать логическое значение из функций, которые являются предикатами некоторой формы, например is_empty (), has_dependencies (), can_fit () и т. Д.и, как правило, выдает исключение при ошибке.В качестве альтернативы, используйте конкретное значение подсистемы (и, возможно, потока) для кодов ошибок согласно errno libc или примите отдельный аргумент ссылки / указателя на переменную, которая будет загружена с кодом ошибки.

0 голосов
/ 22 сентября 2010

Вы отметили свой вопрос как [c] и [c++]. Что он? Потому что ответ будет несколько отличаться.

Вы сказали:

Я заметил, что общее соглашение о кодировании для успешного завершения предполагаемой функциональности метода равно 0.

Для C это нормально.

Для C ++ это определенно , а не . C ++ имеет другой механизм сигнализации о сбое (а именно, исключения). Злоупотребление (числовыми) возвращаемыми значениями для этого обычно является признаком плохого дизайна.

Если исключения по каким-либо причинам не разрешены, существуют другие способы сообщить об ошибке, не забивая тип возвращаемого значения метода. Альтернативы включают в себя возврат bool (рассмотрим метод try_insert) или использование недопустимого / зарезервированного возвращаемого значения для сбоя, например string::npos, который используется методом string::find, когда в строке не найдено ни одного вхождения.

0 голосов
/ 22 сентября 2010

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

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

Тогда есть exit. Это отличается, потому что возвращаемое значение должно интерпретироваться не C, а оболочкой. И здесь значение 0 означает успех, а любое другое значение означает состояние ошибки (многие инструменты сообщают вам, какой тип ошибки произошел с этим значением). Это связано с тем, что в оболочке у вас обычно есть диапазон 0-127 для возврата значимых значений (исторические причины, это байт без знака, и все, что выше 127, означает уничтожение каким-либо сигналом IIRC).

...