C ++ - enum против const против #define - PullRequest
28 голосов
/ 22 января 2011

В конце статьи здесь: http://www.learncpp.com/cpp-tutorial/45-enumerated-types/, упоминается следующее:

Наконец, как и в случае константных переменных, перечисляемые типы отображаются в отладчике, делая их более полезными, чем #defined значения в этом отношении .

Как достигается смелое предложение выше?

Спасибо.

Ответы [ 7 ]

29 голосов
/ 22 января 2011

Рассмотрим этот код,

#define WIDTH 300

enum econst
{
   eWidth=300
};

const int Width=300;

struct sample{};

int main() 
{
        sample s;
        int x = eWidth * s; //error 1
        int y = WIDTH * s;  //error 2
        int z = Width * s;  //error 3
        return 0;
}

Очевидно, что каждое умножение приводит к ошибке компиляции, , но посмотрите, как GCC генерирует сообщения для каждой ошибки умножения:

prog.cpp: 19: ошибка: не соответствует ‘Оператор *’ в ‘eWidth * s ’
prog.cpp: 20: ошибка: не соответствует ‘Оператор *’ в ’300 * с’
prog.cpp: 21: ошибка: не соответствует ‘Оператор *’ в ‘Ширина * с’

В сообщении об ошибке вы не видите макрос WIDTH, который вы #defined, верно? Это потому, что к тому времени, когда GCC делает любую попытку компилировать строку, соответствует второй ошибке, он не видит WIDTH, все видит только 300, как до того, как GCC компилирует строку, препроцессор уже имеет уже заменил WIDTH на 300. С другой стороны, ничего подобного не происходит с enum eWidth и const Width.

Смотри сами ошибки здесь: http://www.ideone.com/naZ3P


Кроме того, прочитайте Скотт Мейерс Item 2 : Prefer consts, enums, and inlines to #defines из Effective C ++ .

14 голосов
/ 02 сентября 2013

enum - постоянная времени компиляции с отладочной информацией без выделения памяти.

const выделяется с хранилищем, в зависимости от того, оптимизирован ли он компилятором с постоянным распространением.

#define не имеет выделения памяти.

6 голосов
/ 22 января 2011

#define значения заменяются препроцессором на значение, которое они объявлены, поэтому в отладчике он видит только значение, а не #defined name, например, если у вас есть #define NUMBER_OF_CATS 10 вв отладчике вы увидите только 10 (поскольку препроцессор заменил каждый экземпляр NUMBER_OF_CATS в вашем коде на 10.

Перечислимый тип сам по себе является типом, а значения являются постоянными экземплярами этого типа, ипоэтому препроцессор оставляет его в покое, и вы увидите символическое описание значения в отладчике.

3 голосов
/ 22 января 2011

Компилятор сохраняет информацию перечисления в двоичном виде, когда программа компилируется с определенными параметрами.

Когда переменная имеет тип перечисления, отладчик может показать имя перечисления.Лучше всего это показать на примере:

enum E {
    ONE_E = 1,
};

int main(void)
{
    enum E e = 1;

    return 0;
}

Если вы скомпилируете это с gcc -g, вы можете попробовать следующее в gdb:

Reading symbols from test...done.
(gdb) b main
Breakpoint 1 at 0x804839a: file test.c, line 8.
(gdb) run
Starting program: test 

Breakpoint 1, main () at test.c:7
7               enum E e = 1;
(gdb) next
9               return 0;
(gdb) print e
$1 = ONE_E
(gdb) 

Если вы использовали определение, у вас не будет правильного типа для выдачи e, и вам придется использовать целое число.В этом случае компилятор выведет 1 вместо ONE_E.

. Флаг -g просит gdb добавить отладочную информацию в двоичный файл.Вы даже можете увидеть, что он там есть, набрав:

xxd test | grep ONE_E

Я не думаю, что это будет работать во всех архитектурах.

0 голосов
/ 29 декабря 2013

Проверьте следующую статью, хорошее резюме http://www.queryhome.com/26340/define-vs-enum-vs-constant

0 голосов
/ 30 июля 2013

Я отвечаю слишком поздно, но чувствую, что могу что-то добавить - enum vs. const против # define

enum -

  1. Не требует вспомогательных значений (если просто нужно иметь последовательные значения 0, 1, 2 ..), тогда как в случае #defines вам нужно вручную управлять значениями, которые могут иногда вызвать человеческую ошибку
  2. Работает так же, как переменная, чтобы во время онлайн-отладки значение enum можно было наблюдать в окне просмотра
  3. У вас может быть переменная типа enum, которой вы можете назначить enum

    typedef enum numbers { DFAULT, CASE_TRUE, CASE_OTHER, };

    int main (пусто) { число число = CASE_TRUE; }

const -

  1. Он постоянно хранится в области памяти, доступной только для чтения, но доступ к нему можно получить по адресу, который невозможен в случае #define
    1. У вас в руках проверка типа, если вы используете const, а не # define
  2. определяет директиву предварительной обработки, но const - время компиляции например

    const char * name = "vikas";

Вы можете получить доступ к имени и использовать его базовый адрес для чтения, например, vikas [3] для чтения 'a' и т. Д.

# определяет - являются тупыми директивами препроцессора, который делает текстовую замену

0 голосов
/ 22 января 2011

По крайней мере для Visual Studio 2008, которая у меня есть под рукой, это предложение является правильным.Если у вас есть

#define X 3
enum MyEnum
{
    MyX = 3
};

int main(int argc, char* argv[])
{
    int i = X;
    int j = (int)MyX;
    return 0;
}

и вы установили точку останова в main, вы можете навести указатель мыши на «MyX» и увидеть, что значение равно 3. Вы не увидите ничего полезного, если наведите курсор на X.

Но это не свойство языка, а поведение IDE.Следующие версии могут сделать это по-другому, как и другие IDE.Так что просто проверьте это в вашей IDE, чтобы увидеть, применимо ли это предложение в вашем случае.

...