Плохая идея смешивать bool- и ret-коды

#c #boolean #return-value #typeerror #return-code

#c #логическое #возвращаемое значение #ошибка типа #return-code

Вопрос:

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

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

Что бы вы порекомендовали? Я пропускаю некоторые предупреждения в gcc, которые предупреждали бы в этих случаях?

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

Ответ №1:

Это плохая идея? Нет, вы должны делать то, что имеет смысл, а не следовать какому-то абстрактному правилу (подобные которому почти никогда не подходят для всех ситуаций, с которыми вы все равно столкнетесь).

Один из способов избежать проблем — убедиться, что все функции, возвращающие логическое значение, читаются как правильные английские, примерами которых являются isEmpty() , userFlaggedExit() или hasContent() . Это отличается от моих обычных глагольно-существительных конструкций, таких как updateTables() , deleteAccount() или crashProgram() .

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

Во всех этих случаях, возвращающих логическое значение, я могу создать легко читаемый if оператор:

 if (isEmpty (list)) ...
if (deleteAccountWorked (user)) ...
  

И так далее.

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


Но имейте в виду, что это мое решение. Это может сработать, а может и не сработать для других людей.

Ответ №2:

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

Ответ №3:

При стандартизации по схеме ноль == ошибка, вы можете смешивать и сопоставлять как enum, так и bool, если вы строите свои тесты следующим образом:

ошибка = some_func(); если !ошибка…

Поскольку первое перечисление равно нулю, а также случай успеха, он идеально соответствует возврату ошибки bool.

Однако, в целом, лучше возвращать значение int (или enum), поскольку это позволяет расширить возвращаемые коды ошибок без изменения вызывающего кода.

Комментарии:

1. Разве это не было бы скорее равно нулю!= ошибка? Потому что для перечисления имеет смысл иметь 1 код ok и n кодов ошибок, а не наоборот.

2. Ну нет, операция имеет 0 как успех (на самом деле довольно распространенный), так что!ошибка … «do some stuff» работает так, как задумано.

3. очень распространено, поскольку перечисления по умолчанию начинаются с 0.

4. больше похоже на return_code != успех, но иногда я мог бы сделать actually_a_bool != success_value_which_is_equal_to_zero .присвоение имени переменной var_bool настолько уродливо.

Ответ №4:

Я бы не сказал, что это плохая практика.

Нет необходимости создавать тонны enum -ов, если вам просто нужно вернуть true / false , и у вас нет других вариантов (и true и false достаточно пояснительны).

Кроме того, если ваши функции будут названы нормально, у вас будет меньше «ошибок».

Например — IsBlaBla — ожидает возврата true . Если у вас есть [Do|On]Reload , перезагрузка может завершиться неудачей по многим причинам, что enum было бы ожидаемо. То же самое для IsConnected и Connect и т.д.

Комментарии:

1. Перечисления являются ошибочными перечислениями из внешних библиотек.

2. А, понятно, я пропустил эту часть.

Ответ №5:

Здесь помогает именование функций IMHO.

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

Комментарии:

1. Обратите внимание, что они подразумевают различное поведение. do_xyz() обычно означает, что функция имеет побочные эффекты, в то время как is_xyz() обычно используется для предикатов, которые не вызывают (наблюдаемых) изменений состояния.

2. @efotinis: Да, это тоже. По совпадению, почти все мои функции, которые возвращают bool, являются функциями без побочных эффектов. Часто, когда функция имеет побочные эффекты, существует множество способов сбоя, и, следовательно, код ошибки является лучшим выбором, чем логическое значение. В любом случае, кажется, что ответ paxdiablo изложил мои мысли более подробно.