реклама на сайте
подробности

 
 
> C++: #define vs. const, Что целесообразнее применять?
haker_fox
сообщение Jun 22 2007, 01:58
Сообщение #1


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



Здравствуйте! До недавнего времени я использовал только си. В настоящее время я стараюсь писать максимально на языке си++, правда мои старания пока ограничиваются классами и некоторыми другими возможностями этого языка. Суть моего вопроса: каким образом может сказаться использование только одних #define, вместо рекомендуемых const?
Просто для меня лично более понятно это:
Код
/* Valve's pin */
#define    VLV_TURN_LEFT_PIN        0
#define    VLV_TURN_RIGHT_PIN        1
#define    VLV_UP_PIN                2
#define VLV_DOWN_PIN                    3
#define    VLV_FORWARD_PIN                4
#define    VLV_BACK_PIN                    5
#define    VLV_OPEN_PIN                    6
#define    VLV_CLOSE_PIN                    7

Чем примерно такое:
Код
const int VLV_TURN_LEFT_PIN 0
и т.д.

В данном случае конечно можно использовать (как я правильно понял) enum.
Но мне нравятся дефайны. Может ли иметь это какие-либо неприятные последствия в будущем?
Заранее спасибо за ответы и сорри за ламерский вопрос...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
dxp
сообщение Jun 22 2007, 07:04
Сообщение #2


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(haker_fox @ Jun 22 2007, 08:58) *
Здравствуйте! До недавнего времени я использовал только си. В настоящее время я стараюсь писать максимально на языке си++, правда мои старания пока ограничиваются классами и некоторыми другими возможностями этого языка. Суть моего вопроса: каким образом может сказаться использование только одних #define, вместо рекомендуемых const?
Просто для меня лично более понятно это:
Код
/* Valve's pin */
#define    VLV_TURN_LEFT_PIN        0
...
#define    VLV_CLOSE_PIN                    7

Чем примерно такое:
Код
const int VLV_TURN_LEFT_PIN 0
и т.д.

В данном случае конечно можно использовать (как я правильно понял) enum.
Но мне нравятся дефайны. Может ли иметь это какие-либо неприятные последствия в будущем?
Заранее спасибо за ответы и сорри за ламерский вопрос...

Дефайн - и в С, и в С++ это просто тупой макрос, тупой в том смысле, что когда он встречается, то производится просто тупая макроподстановка безо всякого анализа того, что получается в результате. Это зачастую является источником труднообнаруживаемых багов - в исходном коде одно, а компилятор видит другое.

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



Цитата(DRUID3 @ Jun 22 2007, 10:09) *
А const int VLV_TURN_LEFT_PIN = 0; это переменная типа int с именем VLV_TURN_LEFT_PIN и равная "0" которую нельзя изменять. Она лежит в памяти (как во Flash так и в RAM во время исполнения).

Это в С она лежит в памяти. Из-за того, что у константных объектов в С по умолчанию внешнее связывание. А в С++ у константных объектов по умолчанию внутреннее связывание, что позволяет компилятору оптимизировать константу и не размещать ее в памяти - все приличные компиляторы сегодня это умеют. В памяти констатный объект обязан быть размещен только в двух случаях:

1. Явно указано внешнее связывание этого объекта - с помощью ключевого слова extern.
2. В коде присутствует взятие адреса этого константного объекта.

В обоих этих случах компилятору ничего не остается, как разместить объект памяти. В других случаех это не не обязательно, чем и пользуется оптимизатор компилятора. Итого, использование того же
Код
// file.h
int a = 10;
...
void f(int x);

// file.cpp
...
f(a);

не приведет ни к какому размещению константы 'a' в памяти - будет точно такая же подстановка, как и в случае с макросом. Но уже с контролем типов.

Цитата(DRUID3 @ Jun 22 2007, 10:09) *
А уж enum, да, это злобный агент C++. В "+ы" перечислениям ставят то, что при инициализации констант компилятор может выполнить проверку типов

О какой проверке типов идет речь?

Цитата(DRUID3 @ Jun 22 2007, 10:09) *
(1). А еще, поскольку перечисления - это типы, определенные пользователем то для них можно перегрузить операции

Типами, определяемыми пользователем, в С++ являются классы и только они. Для них, действительно, можно перегрузить операции. Перечислымый тип enum не является типом, определяемым пользователем, и для него никакие операции перегрузить нельзя.

Единственным назначением перечислимых типов является ограничение принимаемых значений с возможностью задания им сивмолических имен. Перечислимый тип даже не вводит своего пространства имен (scope) и имена его значений видны в том пространстве имен, где он объявлен.

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



Цитата(scifi @ Jun 22 2007, 12:47) *
Я где-то читал, что если не использовать виртуальные функции, то всё, что делается на Си++, можно сделать и на Си. Так что стоит ли огород городить?

И виртуальные функции - точнее, функциональность, реализуемую ими, можно достаточно просто реализовать на С. И вообще, любую программу можно написать на ассемблере.

Цитата(scifi @ Jun 22 2007, 12:47) *
Моё личное мнение - никаких проблем с #define я тут не вижу.

Например, такую проблему Вы не видите?

Код
#define DOUBLE(x) x+x

int a = 3*DOUBLE(4);


Что ожидаем получить? Ожидаем получить 3*8 = 24. А на деле что получим? А получим 3*4+4 = 16. Конечно, этот известный, описанный в учебниках эффект легко обходится с помощью применения скобок:

#define DOUBLE(x) (x+x)

Но там и кроме этого приколов хватает. По той же причине - скрытая от программиста подстановка значений безо всякого контроля со сторны компилятора. Именно по этой причине препроцессор в кодогенерации маст дай.

Цитата(scifi @ Jun 22 2007, 12:47) *
Как верно сказал DRUID3, enum хорош тем, что возможна проверка типов, но при этом придётся его явно преобразовывать к int там, где это нужно.

Какая именно провека типов имеется в виду?

Цитата(scifi @ Jun 22 2007, 12:47) *
Конечно, пуристы из лагеря Си++ скажут, что #define - это тяжёлое наследие Си, и что в Си++ есть средства получше. Но только Вам решать, что использовать, а что нет.

Дефайны - это наследине С. Насколько тяжелое, не берусь судить. Иногда весьма тяжеловатое. Дабы избежать пробем с дефайнами и макропостановкой, надо просто всякую вещь использовать к месту - макросы в условной компиляции, тут им замены пока нет, а в качестве констант использовать константные объекты, в качестве макрофункций - встраевыемые (inline) функции, к качестве генераторов кода - шаблоны.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 22 2007, 07:46
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(dxp @ Jun 22 2007, 10:04) *
В С enum штука почти вообще безполезная - с объектами этого типа можно делать все, что угодно - присваивать им любые значения, производить арифметические действия. Словом, он по сути не отлчичается от обычных интегральных встроенных типов.

Ну не перегибайте палку smile.gif. В абсолютно подавляющем большинстве случаев и в 'C' enum нормально выполняет свою функцию. Да его можно постараться обмануть, да многое отдано на откуп компиляторам и некоторые компиляторы на, например, арифметические действия с enum и wanings не выдадут.... Но "почти вообще бесполезная" это явный перебор - настоятельно рекомендую пользоваться и не ограничиваться банальными #define.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2007, 08:50
Сообщение #4


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(zltigo @ Jun 22 2007, 14:46) *
Ну не перегибайте палку smile.gif. В абсолютно подавляющем большинстве случаев и в 'C' enum нормально выполняет свою функцию. Да его можно постараться обмануть, да многое отдано на откуп компиляторам и некоторые компиляторы на, например, арифметические действия с enum и wanings не выдадут.... Но "почти вообще бесполезная" это явный перебор -

Вы хотите сказать, что на:

Код
enum
{
    SLON = 10,
    MAMONT= 15,
    KOT
} a;

a = 12;


компилятор С дает ошибку?

Мой опыт говорит, что не дает, и по Стандарту не должен - это не запрещенное действие. Максимум компилятор может выдать предупреждение. IAR для AVR, например, дает на этот код предупреждение:

"slon.cpp",15 Warning[Pe188]: enumerated type mixed with another type

типа, смешение типов.

А на

а++;

даже и предупреждения не дает (не обязан). Хотя тут арифметика - т.е. преобразование к целому, инкремент, присваивание.


На

a = SLON + KOT;

тоже дает то же предупреждение, что и в первом примере. В общем, как хочет, так и предупреждает. Но ошибки тут нет. Хотя все эти операции приводят к семантическим ошибкам - объект перечислимого типа принимает значения, которых в типе нет. Именно поэтому в С enum и безполезен именно как перечислимый тип.

А в С++ режиме ни один из этих номеров не проходит. О чем и шла речь. В С++ enum - это отдельный тип и неявных преобразований в него нет. А в С - это некий объект интегрального типа, а не именно тип с перечисленными значениями.

Цитата(zltigo @ Jun 22 2007, 14:46) *
настоятельно рекомендую пользоваться и не ограничиваться банальными #define.

Мне, к счастью, С компиляторами пользоваться не приходится, у меня везде С++, поэтому перечислимыми типами пользуюсь с удовольствим и к месту - они свою роль (описанную в предыущем посте) успешно выполняют.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 22 2007, 11:05
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(dxp @ Jun 22 2007, 11:50) *
компилятор С дает ошибку?
Мой опыт говорит, что не дает, и по Стандарту не должен - это не запрещенное действие.

С опциями типа 'warnings are errors' - да smile.gif
Мне достаточно warning, ибо warnig для меня лично потенциальная ошибка и следует эту проблему решать растолковывая компилятору, что от него требуетя. В крайнем случае индивидуальное подавление прагмой. Наличе warnings и подавление их оптом не приемлю категорически.
Цитата
А на
а++;
даже и предупреждения не дает (не обязан). Хотя тут арифметика - т.е. преобразование к целому, инкремент, присваивание.

Не выдает не обязан и не может - формально отсутсвуюет поминание enum-ов sad.gif. Практически во всех остальных случаях, коих много больше, предупреждения есть.
Цитата
Мне, к счастью, С компиляторами пользоваться не приходится, у меня везде С++, поэтому перечислимыми типами пользуюсь с удовольствим и к месту - они свою роль (описанную в предыущем посте) успешно выполняют.

Я обычно даже 'С' (с легкой доработкой напильником) исходники плюсовым компилятором компилю из-за большей его привередливости и небольших приятных фич, но тем не менее настаиваю на полезности использования enum и в "C".


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2007, 13:15
Сообщение #6


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(zltigo @ Jun 22 2007, 18:05) *
С опциями типа 'warnings are errors' - да smile.gif
Мне достаточно warning, ибо warnig для меня лично потенциальная ошибка и следует эту проблему решать растолковывая компилятору, что от него требуетя. В крайнем случае индивидуальное подавление прагмой. Наличе warnings и подавление их оптом не приемлю категорически.

Я тоже не сторонник подавлять предупреждения скопом и никогда так не делаю. Но тем не менее предупреждение - это совсем не ошибка. Это указание на место потенциальной ошибки, не более.

Цитата(zltigo @ Jun 22 2007, 18:05) *
Не выдает не обязан и не может - формально отсутсвуюет поминание enum-ов sad.gif. Практически во всех остальных случаях, коих много больше, предупреждения есть.

Как это отсутствует? 'a' - это объект перечислимого типа, вот и поминание. К нему применяется операция инкремента, которая приводит значение объекта к величине, отсутствующей в типе этого объекта. Это есть не что иное, как семантическая ошибка! Объект 'a' перечислимого типа на деле перестает таковым быть! И в чем тогда смысл использования перечисления? Вот в С++ правила строго защищают эту ситуацию - перечислимый тип является таковым, любая попытка нарушить целостность типа объекта пресекается ошибкой. Это и делает enum перечислимым типом. Это и обуславливает целесообразность использования.

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

Цитата(zltigo @ Jun 22 2007, 18:05) *
но тем не менее настаиваю на полезности использования enum и в "C".


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jun 22 2007, 14:05
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(dxp @ Jun 22 2007, 16:15) *
В С этого нет, поэтому enum в С штука почти бесполезная - годится только для описания именованных литералов, не более.

smile.gif
Как известно, всегда существуют 100% эффективные средства для решения проблемы. Например, проблему перхоти хорошо решает гильотитна, но почему при наличии гильотины не пользоваться не столь эффективным шампунем против перхоти я не занаю smile.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2007, 14:19
Сообщение #8


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(zltigo @ Jun 22 2007, 21:05) *
smile.gif
Как известно, всегда существуют 100% эффективные средства для решения проблемы. Например, проблему перхоти хорошо решает гильотитна, но почему при наличии гильотины не пользоваться не столь эффективным шампунем против перхоти я не занаю smile.gif.

Пример забавный smile.gif, но не в кассу - у гильотины побочный эффект нехороший. В перечислимом типе С++ никаких таких побочных эффектов нет. А в С от перечислимого типа только название. Думается, что Вы не будете в восторге от использования для мытья волос воды, даже если на ней написно "Шампунь". biggrin.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- haker_fox   C++: #define vs. const   Jun 22 2007, 01:58
- - DRUID3   Чивото я совсем не понял ничего в Вашем вопросе ...   Jun 22 2007, 03:09
|- - haker_fox   Цитата(DRUID3 @ Jun 22 2007, 11:09) Чивот...   Jun 22 2007, 04:55
- - Losik   основной смысл в том, что >>при инициализаци...   Jun 22 2007, 05:47
- - scifi   Цитата(haker_fox @ Jun 22 2007, 05:58) До...   Jun 22 2007, 05:47
||- - rezident   Цитата(dxp @ Jun 22 2007, 20:19) А в С от...   Jun 22 2007, 14:26
|||- - dxp   Цитата(rezident @ Jun 22 2007, 21:26) А р...   Jun 23 2007, 03:38
|||- - rezident   Цитата(dxp @ Jun 23 2007, 09:38) Если объ...   Jun 23 2007, 13:04
|||- - CaPpuCcino   Цитата(dxp @ Jun 23 2007, 07:38) Контроль...   Jun 23 2007, 20:06
||- - zltigo   Цитата(dxp @ Jun 22 2007, 17:19) Думается...   Jun 22 2007, 14:29
|- - CaPpuCcino   Цитата(dxp @ Jun 22 2007, 11:04) Код// fi...   Jun 22 2007, 18:26
- - HSC   Практически все что было сказано выше в этой ветке...   Jun 22 2007, 08:30
|- - zltigo   Цитата(HSC @ Jun 22 2007, 11:30) Представ...   Jun 22 2007, 08:45
- - XVR   Хочу добавить свои 5 коп. к всему вышеизложенному:...   Jun 22 2007, 09:31
- - sergeeff   Вообще подобные вопросы неплохо разложены в книге ...   Jun 23 2007, 21:32


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 19:43
Рейтинг@Mail.ru


Страница сгенерированна за 0.01491 секунд с 7
ELECTRONIX ©2004-2016