Разница между перечислением и определением утверждений - PullRequest
45 голосов
/ 26 сентября 2008

В чем разница между использованием оператора define и оператора enum в C / C ++ (и есть ли разница при использовании их с C или C ++)?

Например, когда следует использовать

enum {BUFFER = 1234}; 

над

#define BUFFER 1234   

Ответы [ 18 ]

56 голосов
/ 26 сентября 2008

enum определяет синтаксический элемент.

#define - это директива препроцессора, выполняемая за до , компилятор видит код и, следовательно, не является языковым элементом самого языка C.

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

17 голосов
/ 26 сентября 2008

#define операторы обрабатываются препроцессором до того, как компилятор увидит код, поэтому это в основном текстовая подстановка (на самом деле это немного более разумно с использованием параметров и тому подобного).

Перечисления являются частью самого языка Си и имеют следующие преимущества.

1 / Они могут иметь тип, и компилятор может проверять их тип.

2 / Поскольку они доступны для компилятора, информация о символах на них может передаваться отладчику, что облегчает отладку.

8 голосов
/ 26 сентября 2008

Определить - это команда препроцессора, она аналогична выполнению команды «заменить все» в вашем редакторе, она может заменить строку другой и затем скомпилировать результат.

Enum - это особый случай типа, например, если вы пишете:

enum ERROR_TYPES
{
   REGULAR_ERR =1,
   OK =0
}

существует новый тип с именем ERROR_TYPES. Это правда, что REGULAR_ERR уступает 1, но приведение этого типа к int должно привести к предупреждению о приведении (если вы настроите свой компилятор на высокую детализацию).

Резюме: они оба похожи, но при использовании enum вы получаете выгоду от проверки типов, а с помощью определения вы просто заменяете строки кода.

5 голосов
/ 26 сентября 2008

Перечисления обычно предпочтительнее, чем #define, везде, где имеет смысл использовать перечисление:

  • Отладчики могут показать вам символическое имя значения enum s ("openType: OpenExisting", а не "openType: 2"
  • Вы получаете немного больше защиты от столкновений имен, но это не так плохо, как было (большинство компиляторов предупреждают о повторности #define.

Самая большая разница в том, что вы можете использовать перечисления как типы:

// Yeah, dumb example
enum OpenType {
    OpenExisting,
    OpenOrCreate,
    Truncate
};

void OpenFile(const char* filename, OpenType openType, int bufferSize);

Это дает вам проверку типов параметров (вы не можете так легко смешать openType и bufferSize) и упрощает поиск допустимых значений, делая ваши интерфейсы намного проще в использовании. Некоторые IDE могут даже дать вам intellisense завершение кода!

4 голосов
/ 14 июня 2010

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

Для реализации, например. куча режимов, использование перечисления позволяет компилятору отлавливать, например, пропущенные case -условия в переключателе.

3 голосов
/ 14 июня 2010

enum может группировать несколько элементов в одну категорию:

enum fruits{ apple=1234, orange=12345};

в то время как #define может создавать только несвязанные константы:

#define apple 1234
#define orange 12345
3 голосов
/ 14 июня 2010

# define - это команда препроцессора, enum на языке C или C ++.

Всегда лучше использовать перечисления вместо #define для такого рода случаев. Одна вещь - это безопасность типов. Другая причина состоит в том, что когда у вас есть последовательность значений, вам нужно только указать начало последовательности в перечислении, остальные значения получат последовательные значения.

enum {
  ONE = 1,
  TWO,
  THREE,
  FOUR
};

вместо

#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4

В качестве дополнительного примечания, все еще есть случаи, когда вам, возможно, придется использовать #define (обычно для каких-то макросов, если вам нужно создать идентификатор, содержащий константу), но это макро черная магия, и очень, очень редкий путь. Если вы выходите на эти конечности, вам, вероятно, следует использовать шаблон C ++ (но если вы застряли с C ...).

2 голосов
/ 14 июня 2010

Если вы хотите только эту единственную константу (скажем, для размера буфера), я бы не использовал перечисление, а просто определение. Я бы использовал перечисления для таких вещей, как возвращаемые значения (которые означают разные условия ошибки) и везде, где нам нужно различать разные «типы» или «случаи». В этом случае мы можем использовать enum для создания нового типа, который мы можем использовать в прототипах функций и т. Д., И тогда компилятор сможет лучше проверить этот код.

2 голосов
/ 14 июня 2010

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

Использование #define обычно не проблема, но, поскольку у enum нет недостатков, я согласен с этим.

В C ++ я также обычно предпочитаю enum const int, хотя в C ++ const int может использоваться вместо целочисленного литерального значения (в отличие от C), потому что enum является переносимым для C (который я еще много работаю).

2 голосов
/ 14 июня 2010

Помимо всего того, что уже написано, один сказал, но не показан, и вместо этого интересно. Э.Г.

enum action { DO_JUMP, DO_TURNL, DO_TURNR, DO_STOP };
//...
void do_action( enum action anAction, info_t x );

Рассмотрение действия как типа проясняет ситуацию. Используя определение, вы бы написали

void do_action(int anAction, info_t x);
...