Подтвердить что ты не робот

С++ - enum vs. const vs. #define

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

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

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

Спасибо.

4b9b3361

Ответ 1

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

#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: ошибка: нет соответствия для 'Operator * в' eWidth * s
prog.cpp: 20: ошибка: нет соответствия для 'Operator * в' 300 * s
prog.cpp: 21: ошибка: нет соответствия для 'Operator * в' Width * s

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

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


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

Ответ 2

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

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

#define не имеет распределения памяти.

Ответ 3

Значения

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

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

Ответ 4

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

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

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

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

Ответ 5

По крайней мере, для 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;
}

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

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

Ответ 6

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

перечисление -

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

    typedef перечисляет числа { DFAULT, CASE_TRUE, CASE_OTHER, };

    int main (void) { число number = CASE_TRUE; }

const -

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

    const char * name = "vikas";

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

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