С++ - enum vs. const vs. #define
В конце статьи здесь: http://www.learncpp.com/cpp-tutorial/45-enumerated-types/, он упоминает следующее:
Наконец, как и в случае с постоянными переменными, в отладчике отображаются перечисленные типы, делает их более полезными, чем #defined значения в этом отношении.
Как достигается смелое предложение выше?
Спасибо.
Ответы
Ответ 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 -
являются немыми предпроцессорными директивами, которые выполняют текстовую замену
Ответ 7
Проверьте следующую статью, хорошее резюме
http://www.queryhome.com/26340/define-vs-enum-vs-constant