Недавно я придумал, как я полагаю, странный способ объявления статуса возврата функции в c-коде. Функция, выполняющая задачу, часто возвращает код состояния в зависимости от успеха или ошибки. Это часто отправляется как целое число или перечисление, объявленное где-то еще в файле (или другом файле). Я обнаружил, что, объявив перечисление в сигнатуре функции, мы можем:
Например. так:
// implementation.h
enum {
OK,
INTERNAL_ERROR,
NO_PARAMETERS
} do_that();
// implementation.c
enum {
OK,
INTERNAL_ERROR,
NO_PARAMETERS
} do_that() {
if (this())
return OK;
else if (that())
return NO_PARAMETERS;
return INTERNAL_ERROR;
}
Я никогда не видел, чтобы кто-нибудь использовал этот стиль; это действительно? Если нет, то почему?
Один недостаток, который я вижу, заключается в том, что вы должны указать возможные возвращаемые значения как в c-файле, так и в заголовочном файле, но это также делает его более доступным и понятным непосредственно при просмотре подписи.
Другая проблема заключается в том, что, насколько я понимаю, неявное преобразование между enum-типами разрешено даже в педантичном c, это означает, что объявление разных состояний возврата в объявлении и реализации функции (файл c и h) не будет генерировать предупреждение или ошибку.
Каким компилятором вы компилируете этот код? gcc недоволен из-за переопределений...
Даже если значения перечислителя идентичны, я не уверен, что это законно C. Если значения перечислителя каким-либо образом отличаются, то это определенно не так, что делает метод бесполезным. Тем не менее, это интересный вопрос, если значения идентичны, как вы представляете.
@Closers: как, черт возьми, основано это мнение?
Каждый файл является независимым и пригодным для использования. Чего вы не можете сделать, так это включить implementation.h в implementation.c, что означает, что вы потеряете перекрестную проверку, которую обычно обеспечивают заголовки.
@Bathsheba Я думаю, это потому, что он спрашивал плюсы и минусы определенного стиля программирования. Это не по теме, потому что то, что люди считают плюсами и минусами, часто основано на личном мнении. Я отредактировал вопрос, чтобы удалить этот язык и отразить то, что на самом деле обсуждается здесь.





Одна из серьезных проблем заключается в том, что вы не можете использовать компилятор для перекрестной проверки заголовка и реализации, потому что реализация TU (единица перевода) — то есть implementation.c в вопросе — не может включать заголовок (implementation.h), потому что константы перечисления будут быть дважды определенным, что не допускается. Это означает, что компилятор не может обнаружить несоответствия между поставщиком и потребителями службы. Потребители могут использовать заголовок, а поставщик (implementation.c) — нет.
Кроме того, только одна функция может использовать OK (или INTERNAL_ERROR, или NO_PARAMETERS) — другим функциям нужны разные имена для состояния «нет ошибки» и разные имена для каждого из состояний ошибки. Следовательно, это непрактичное решение даже для небольшого программного обеспечения, даже если его можно использовать для одной функции (но это не очень хорошая идея).
Кстати, обратите внимание, что хотя для do_that() есть объявления, его прототипа нет ни в заголовке, ни в файле реализации. Функция объявлена принимающей неопределенный список параметров — все, что известно, это то, что формально она не является вариационной функцией (без многоточия ...), и все ее аргументы подчиняются правилам продвижение аргумента по умолчанию (примерно: char и short повышаются до int; float повышается до double). Если функция не принимает аргументов, она должна быть записана как do_that(void), чтобы прототип был доступен после завершения объявления.
Это недопустимо, так как первое перечисление отличается от второго перечисления, поэтому объявление и определение имеют несовместимые подписи, даже если их постоянные члены идентичны.
Цитата из 6.2.5 Типы с. 16
Each distinct enumeration constitutes a different enumerated type
Это тот. Спасибо.
Это относится к одному TU. На кону в разных TU стоят разные вопросы. См. §6.2.7 Совместимый тип и составной тип для некоторых правил, касающихся определений, совместно используемых TU.
Как это может сделать их несовместимыми? 6.2.7 В §1 говорится, что типы совместимы.
«Более того, две структуры, объединения или перечисляемые типы, объявленные в отдельных единицах перевода, совместимы, если их теги и члены удовлетворяют следующим требованиям: если один объявлен с тегом, другой должен быть объявлен с тем же тегом. Если оба завершены где-либо в пределах своих соответствующих единиц перевода, то применяются следующие дополнительные требования: между их элементами должно быть однозначное соответствие, так что каждая пара соответствующих членов объявляется с совместимыми типами; /--/ "Для двух перечислений соответствующие элементы должны иметь одинаковые значения."
Пытающийся:
#include <stdio.h>
// implementation.h
enum {
OK,
INTERNAL_ERROR,
NO_PARAMETERS
} do_that();
// implementation.c
enum {
OK,
INTERNAL_ERROR,
NO_PARAMETERS
} do_that() {
if (mytest == 0)
return OK;
else if (mytest == 1)
return NO_PARAMETERS;
return INTERNAL_ERROR;
}
int main()
{
printf("do_that(%d) = %d\n",0,do_that(0));
printf("do_that(%d) = %d\n",1,do_that(1));
printf("do_that(%d) = %d\n",2,do_that(2));
return 0;
}
Дает:
Main.c:11:5: error: redefinition of enumerator 'OK'
OK,
^
Main.c:4:5: note: previous definition is here
OK,
Итак, вы не можете:
включите свой .h в .c.
объявить прототип функции
Почему бы вам просто не использовать typedef?
Почему не typedef?