Насколько плохо отказываться от правила в C (иначе: вернуть 0 в случае успеха)? - PullRequest
4 голосов
/ 04 октября 2010

в текущем проекте я осмелился покончить со старым правилом 0, то есть вернуть 0 при успешном выполнении функции. Как это видно в сообществе? Логика, которую я навязываю коду (и, следовательно, сотрудникам и всем последующим программистам обслуживания):

.> 0: для любого успеха / достижения, то есть положительного результата

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

<0: для любого вида ошибки / неосуществимости, то есть <em>отрицательный результат

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

Opininons

PS: на заметку о том, что Римская империя рухнула, потому что римляне, у которых в системе счисления отсутствовала цифра 0, никогда не знали, когда их функции С будут успешными!

Ответы [ 13 ]

10 голосов
/ 04 октября 2010

«Ваша программа должна следовать существующему соглашению, если оно имеет смысл».

Источник: Библиотека GNU C

9 голосов
/ 04 октября 2010

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

http://en.wikipedia.org/wiki/Exit_status

7 голосов
/ 04 октября 2010

Я думаю, вы преувеличиваете статус этого мифического "правила". Гораздо чаще случается так, что функция возвращает неотрицательное значение в случае успеха, указывающее результат какого-либо вида (количество записанных / прочитанных / преобразованных байтов, текущая позиция, размер, значение следующего символа и т. Д.), И эти отрицательные значения, которые в противном случае не имеет смысла для интерфейса, зарезервированы для сигнализации об ошибках. С другой стороны, некоторые функции должны возвращать результаты без знака, но ноль никогда не имеет смысла как действительный результат, а затем ноль используется для сигнализации об ошибках.

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

И, наконец, как уже говорили другие, независимо от вашего соглашения, задокументируйте его!

4 голосов
/ 04 октября 2010

Хорошо, если вы хорошо это задокументируете.

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

Я думаю, что в конечном итоге это зависит от клиентов вашего кода.

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

Однако, если вы пишете API, который можно продавать внешним клиентам, или пишете модуль, который будет подключен к существующему, система "стандартный-RC", я бы посоветовал вам придерживаться правила 0-on-success, чтобы избежать путаницы в будущем и возможных ловушек для других разработчиков.

И согласно вашей PS, когда вРим, делай как римляне: -)

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

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

Однако, в качестве альтернативы, возможно, стоит изучить вариант возврата перечисляемого типа, определяющего коды. Что-то вроде:

enum returnCode {
    SUCCESS, FAILURE, NO_CHANGE
}

Таким образом, гораздо более очевидно, что делает ваш код, даже самодокументирование. Но может быть не вариант, в зависимости от вашей кодовой базы.

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

Я думаю, вы должны следовать Принципу Наименьшего Изумления

Пола заявляет, что когда два элементы конфликта интерфейса, или неоднозначны, поведение должно быть то, что меньше всего удивит пользователь; в частности, программист должен попытаться думать о поведении это меньше всего удивит того, кто использует программу, а не поведение, которое естественно знать внутренняя работа программы.

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

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

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

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

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

Вы должны идти на индивидуальной основе. Подумайте об API и что вам нужно вернуть. Если вашей функции нужно только возвращать успех или неудачу, я бы сказал, дал бы ей явный тип bool (C99 теперь имеет тип bool) и вернул true для успеха и false для сбоя. Таким образом, такие вещи, как:

if (!doSomething())
{
    // failure processing
}

читать естественно.

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

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

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

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

Я бы нашел другой метод для передачи статуса между процессами. Есть из чего выбирать, некоторые довольно простые. Вы говорите «ценой нескольких WTF на стороне программистов», как будто это небольшая стоимость, но для меня это звучит как огромная цена. Повторное использование int в C - это минимальное преимущество, которое можно получить, запутав других программистов.

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