Могу ли я вернуть EXIT_(СБОЙ|УСПЕХ) из функции?

#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, когда команда не возвращала ошибку.