#c #function
Вопрос:
Допустим, я определил функцию, которая возвращает int
флаг для успешного выполнения,
// returns an int representing a successfulness
int not_main_add_element_at_index_of_the_list(list *l, size_t i, void *d) {
// fail when i > l.size
// fail when failed to allocate a node
// ...
// anyway two possible values for the result: success, failure
}
Когда я намереваюсь, должно быть только два вида результатов: успех и неудача, какова бы ни была причина,
могу ли я вернуться EXIT_FAILURE
или EXIT_SUCCESS
?
Или мне следует придерживаться bool
этого ?
Комментарии:
1.
bool
это лучший вариант ИМО.2. Я предполагаю, что имена более описательны, чем
true
иfalse
которые бессмысленны, если имя функции не дает представления о том, что они означают.
Ответ №1:
Ты можешь, но не должен. Они зарезервированы для кодов выхода из программы и должны использоваться только с exit
семейством функций или во return
время из main.
Профессиональные API-интерфейсы также обычно не возвращаются bool
для обработки ошибок, так как это очень прямолинейно и не дает никакой информации, кроме » ок » или «сбой». (Как мы знаем из SO, «это не работает» — очень плохое описание ошибки.)
Общая хорошая практика, когда дело доходит до правильного проектирования API, состоит в том, чтобы возвращать пользовательский typedef:ed enum
с кодами ошибок, специфичными для вашего модуля/библиотеки. В вашем случае я ожидал бы увидеть что-то вроде:
list_err_t add_item (/* ... */);
Комментарии:
1. или установите
errno
, если это необходимо.
Ответ №2:
Это субъективный вопрос. Включая stdlib.h
, ничто не мешает вам использовать EXIT_FAILURE
или EXIT_SUCCESS
.
Ты мог бы это сделать.
Как вы уже упоминали, вы также могли бы использовать bool
. Я бы предложил пойти этим путем, потому что это облегчает if
написание выражений if (element_at_index_of_the_list(..))
. Вы найдете это в открытом исходном коде на GitHub
.
Ответ №3:
Возврат EXIT_FAILURE
или EXIT_SUCCESS
из функции, которой main
нет, не является идиоматичным. Это возможно, но я бы определенно избегал этого. Отчасти потому, что всякий раз, когда вы видите одно из них в коде, вы ожидаете, что оно выйдет из программы.
Но также потому, что если у вас есть только два разных возвращаемых значения, то вы обычно хотите использовать возвращаемое значение, которое может быть оценено как true, чтобы означать успех, но два макроса выхода перевернуты. EXIT_SUCCESS
определяется как ноль. Конечно, есть библиотечные функции, которые при успешном выполнении возвращают ноль, но лично я предпочитаю, if(foo())
чтобы при успешном выполнении запускался блок if foo
.
В твоей ситуации я бы bool
тоже не стал использовать а. Я бы вернул указатель на добавленный элемент и NULL
при сбое.
В целом, я бы использовал bool
в качестве возвращаемого типа только функции, с которых имело бы смысл начинать их имя is
. Как isdigit()
, например.
Я также склонен думать о том, какой была бы наиболее полезная отдача. Возвращая указатель на добавленный элемент, вы получаете И этот указатель, И способ проверки на наличие сбоя. Так зачем же выбирать bool
вместо этого?
Те же рассуждения можно использовать, если вы хотите написать функцию для проверки того, содержит ли строка символ. Вы можете либо вернуть значение true, если оно содержит символ, но вы могли бы сделать функцию более полезной, вернув вместо этого количество вхождений. Если, конечно, вам не нужно оптимизировать код.
Комментарии:
1. Возврат EXIT_FAILURE или EXIT_SUCCESS из функции, которая не является основной, не является идиоматичным. Однако, вероятно, что-то вроде половины стандартных функций POSIX, перечисленных здесь , возвращает ноль при успешном выполнении и ненулевое значение при сбое, поэтому возврат нуля при успешном выполнении, безусловно, идиоматичен.
2. @AndrewHenle Хммм, ты прав, но разве это не из-за того, как
bash
работает?3. Или так
bash
работает, потому что именно так работают функции POSIX? Ответ на этот вопрос, вероятно, потребует некоторых археологических раскопок в ранних C и UNIX.4. @AndrewHenle Правда. Однако я не утверждаю, что это не идиоматично-возвращать ноль при успехе. Как вы думаете, мне нужно перефразировать, чтобы избежать путаницы?
5. POSIX имеет 8-разрядные коды выхода, все из которых, кроме 0, интерпретируются командной оболочкой как сбой.
Ответ №4:
Это зависит от того, что вы хотите сделать с результатом. Я бы рекомендовал использовать bool
from stdbool.h, потому что это распространенный шаблон для проверки успеха или сбоя функции таким образом, например
if (my_function()) {
//it worked
}
Но если по какой-то причине вам нужно проверить наличие определенных кодов ошибок, например, EXIT_SUCCESS
вы могли бы использовать его, это просто макрос в stdlib.h. В данном конкретном случае это не имеет особого смысла, так как эти два кода могут быть представлены true
или false
вместо этого, и они действительно предназначены для использования с exit()
функцией. Поэтому было бы лучше определить свои собственные коды ошибок, если вы хотите указать конкретные результаты в возвращаемом значении.
Также обратите внимание, что это EXIT_SUCCESS
соответствует 0 (т. Е. false
), что и следовало ожидать в bash, когда команда не возвращала ошибку.