2008-09-25 2 views
44

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

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

enum {BUFFER = 1234}; 

над

#define BUFFER 1234 

ответ

55

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

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

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

+21

Вы также можете поместить перечисления в пространствах имен, тогда как макросы не могут быть. – 2008-09-26 03:48:50

+0

Однако макросы могут быть легко сконфигурированы вне самого исходного кода (например, из команды построения) – 2016-01-31 17:32:07

8

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

Enum является частным случаем типа, например, если вы пишете:

enum ERROR_TYPES 
{ 
    REGULAR_ERR =1, 
    OK =0 
} 

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

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

+1

«отбрасывание от этого типа до int», как мне кажется, вернулось в начало; C++ рассматривает перечисления как специализации int. – 2008-09-26 00:09:09

1

Если у вас есть группа констант (например, «Дни недели»), перечисления будут предпочтительнее, потому что это показывает, что они сгруппированы; и, как сказал Джейсон, они безопасны по типу. Если это глобальная константа (например, номер версии), это больше того, что вы использовали бы #define; хотя это является предметом многих дебатов.

14

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

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

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

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

5

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

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

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

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

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

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

1

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

1

Еще одно преимущество перечисления в списке определений заключается в том, что компиляторы (по крайней мере, gcc) могут генерировать предупреждение, когда не все значения проверяются в инструкции switch. Например:

enum { 
    STATE_ONE, 
    STATE_TWO, 
    STATE_THREE 
}; 

... 

switch (state) { 
case STATE_ONE: 
    handle_state_one(); 
    break; 
case STATE_TWO: 
    handle_state_two(); 
    break; 
}; 

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

4

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

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

1

перечисления больше используются для перечисления какого-либо набора, например, дней в неделю. Если вам нужно только одно постоянное число, const int (или двойной и т. Д.) Будет определенно лучше, чем перечисление. Мне лично не нравится #define (по крайней мере, не для определения некоторых констант), потому что он не дает мне типа безопасности, но вы можете, конечно, использовать его, если он вам подходит.

2

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

3

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

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

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

#define apple 1234 
#define orange 12345 
+0

Благодарим вас за самый полезный ответ в Интернете. (и я действительно не шучу) – 2013-09-05 05:05:08

3

#define является команда препроцессора, перечисление находится в 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

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

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); 
2

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

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

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

1

Создание enum создает не только литералы, но и тип, который группирует эти литералы: это добавляет семантику вашему коду, который может проверить компилятор.

Кроме того, при использовании отладчика у вас есть доступ к значениям литералов перечисления. Это не всегда относится к #define.

0

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

Некоторые преимущества перечислений заключаются в том, что числовые значения автоматически назначаются, что отладчик может отображать символические значения при проверке переменных перечисления и что они подчиняются области блока. (Компилятор также может генерировать нефатальные предупреждения, когда перечисления смешиваются без разбора, так как делать это можно по-прежнему считаться плохим стилем, даже если он не является строго незаконным.) Недостатком является то, что программист не имеет большого контроля над этими нефатальными предупреждениями; некоторые программисты также возмущены отсутствием контроля над размерами переменных перечисления.

0

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

Например:

 

    #define OPT_X1 1 /* introduced in version 1 */ 
    #define OPT_X2 2 /* introduced in version 2 */ 

Затем программное обеспечение, которое может быть собран с любой версии он может сделать

 

    #ifdef OPT_X2 
    int flags = OPT_X2; 
    #else 
    int flags = 0; 
    #endif 

Хотя на перечисление это невозможно без механизма обнаружения функция времени выполнения ,

1

Enum:

1. Обычно используется для нескольких значений

2. В перечислении существует две вещи одно имя и другое значение имени имени должно быть выделено, но значение может быть same.If мы не определяем значение, то первое значение имени перечисления равно 0 секунде значение равно 1 и так далее, если явно не указано значение.

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

4. делая отладку легкой

5. Мы можем ограничить сферу его до класса.

Определить:

1. Когда мы должны определить только одно значение

2. Как правило, заменять одну строку в другую строку.

3. Это сфера является глобальным, мы не можем ограничить его объем

В целом, мы должны использовать Enum

Смежные вопросы