Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2 3  Все   Вниз
  Печать  
Автор Тема: не могу жить без #define :)  (Прочитано 56713 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« : 09-07-2007 05:21 » 

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

вопрос к противникам этого чуда - какой посоветуете использовать аналог дефайна, против которого Вы не, но который полностью заменит дефайн ?
Записан

nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 09-07-2007 05:50 » 

Смотря для чего ты используешь дефайн. Если ты с его помощью меняешь порядок компиляции в зависимости от версии и т.п., то в принципе используй на здоровье, а для остального вроде бы есть данные и и методы класса.
Записан

ещё один вопрос ...
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #2 : 09-07-2007 07:19 » 

nikedeforest, смотря что ты понимаешь под порядком компиляции...

давай пойдём от обратного - что не стоит делать через дефайн ? (пример приведи)
я потом сравню - если я делаю что то "недопустимое, тогда уточню вопрос
« Последнее редактирование: 09-07-2007 07:21 от Алексей1153++ » Записан

nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 09-07-2007 07:22 » 

ИМХО, не стоит делать макросы и объявлять константы (или как там они называются), т.е.
#define MaxValue 100

Но в принципе не сильно возбраняется делать так
#define bugVersion
#define HomeEdition

#ifdef bugVersion
printf (" ");
...

#ifdef HomeEdition
....



Смысл надеюсь понятен?



« Последнее редактирование: 09-07-2007 07:25 от nikedeforest » Записан

ещё один вопрос ...
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #4 : 09-07-2007 08:52 » 

вот как раз макросов типа
#define MaxValue 100
 - навалом . Но в последнее время стараюсь объявить через enum

а почему так не стоит делать ?
Записан

nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 09-07-2007 09:27 » 

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

ещё один вопрос ...
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #6 : 09-07-2007 09:36 » 

да вот не всегда так получается
Записан

nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 09-07-2007 10:05 » 

А в каких случаях не получается?
Записан

ещё один вопрос ...
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #8 : 09-07-2007 10:57 » 

Лёш, на самом деле никто не сможет тебе ответить на вопрос "почему?". Это всё-равно что спросить почему один любит арбуз, а другой свинной хрящик.

Потому что это по сути ничем не лучше глобальных переменных.

Абсолютно неверно! define (в данном случае) не имеет никакого отношения к переменным. Они не находятся в таблице перепенных они ВОБЩЕ нигде не находятся к моменту компиляции. Об этом позаботится прекомпилятор.

Насчёт того, что define - зло. Бред! С таким же успехом можно утверждать, что столовые приборы - зло, поскольку без них можно обойтись, и кушать например руками.

Данному утверждению нет ни одного доказательства , а вот опровергнуть его можно легко:

В программе, в мат. расчётах во многих местах (чтобы быть совсем точным - в 17ти файлах, 48 классов, всего 397 вхождений) необходимо использовать некую эмпирическую константу, которая равна 423.566783. Через 48 недель, эта константа изменяется и становится равной 273.982647.
И что? Мне надо перелопатить 17 файлов и в каждом поменять значение? Каким образом я должен определить переменную(ые) внутри класса? Или сделать глобальную константу?

А как же быть с системозависимыми? Например MAX_PATH?

define (в данном случае) не имеет также никакого отношения к ООП парадигме. Это просто дополнительная возможность, удобно, читабельно, наконец красиво  оформить код. И С++ здесь совершенно не при чём.

Теперь про макросы.

Нормальная цветовая модель в GDI (COLORREF) для набора кодируется как BGR, что очень неудобно для ввода инфы полученной от дизайнеров, которые все экранные цвета представляют в RGB
Те чтобы видеть в коде "нормальную" цветовую модель, цвета надо преобразовать:

Код:
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))

Таким образом они позоволяют сделать код компактным, а, соответственно, удобочитаемым (легко просматриваемым) в ключевых местах, не загромождая его повторяющимися сложными выражениями.

А вот какой вред от них?
« Последнее редактирование: 09-07-2007 10:59 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 09-07-2007 11:03 » 

Сравнение с глобальными переменными здесь образное, а не буквальное. Ну а если это по-вашему лучший способ оформить код, то мне просто нечего сказать.
Записан

ещё один вопрос ...
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #10 : 09-07-2007 12:12 » 

ИМХО макросы полезны, когда они действительно полезны, т.е. когда использование другого подхода или невозможно или крайне не удобно, что для меня равносильно невозможно

Джон, что касается констант занесённых в макроопределение, так это решается простыми константными переменными, они на этапе компиляции имеют привычку подставлятся в код значением, а не переменной.
опять же есть менанизм enum
макрос могут переопределить в другом хередере и ты это увидишь только в виде предупреждения в большом проекте собираемого системой автосборки ты можешь никогда не обратить внимание на это сообщение или забить на него со словами: " А макрос, да фиг с ним", этого не случится при использовании енумов и константных переменных, потому, что компилятор не соберёт проект и ты будешь вынужден обратить внимание на проблему.
по поводу RGB это прекрасно заменяется шаблонную на inline функцию
+ под отладной не всегда можно увидеть чему всёже был равен макрос в точке отладки.

Впрочем приведённые тобой примеры мне кажутся вполне безобидными. Лично мне не нравятся макросы которые разварачиваются в здоровенную функцию или класс(видел я много таких), тяжелова-то в них отлаживаться

Есть у нас в коде пара мест, где такие страшные макросы вполне оправданны по соображениям производительности, но их всего ничего.
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #11 : 09-07-2007 15:20 » 

ну функции я никогда не засовывал в макросы, только исключительно константы или повторяемые много раз кусаки (во время поиска глюка они ещё не макрос, а потом переделываю в макрос после отладки)

ещё делаю такую вещь (где то упоминал)
Код:
#define num      133
#define num_txt "133"

 - где надо, вставляю число, где надо - предопределённую строку

Ну и константы и несложные выражения-формулы
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #12 : 09-07-2007 17:27 » 

Алексей1153++, ну ведь можно написать функцию Жаль что бы небыло повторяющегося(шаблонунную, если лень в типах разбираться), зачем макрос? зачем? Жаль найдут у тебя тестеры ошибку, из макроса данные обратно в код будешь вставлять, во все места, где он используется? в нём же даже брейкпоинт не поставить.

что касается
Код:
#define num      133
#define num_txt "133"

то у нас делают так
Код:
const int num = 133;
const char * num_txt = "133";
enum { ENum = 133, Enum2 = 266};
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #13 : 09-07-2007 18:04 » 

LogRus,
const char * num_txt = "133";
- это глобальная переменная. Не есть хорошо совсем...

>> ну ведь можно написать функцию 
Можно... с кучей передаваемых параметров. Обычно макросы описываю уже внутри функции (там, где много повторяющихся кусков). Иногда действительно пепеделываю в функторы, но иногда это не удобно, так и остаются макросы

Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 09-07-2007 19:18 » 

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

Совсем отказываться от define также не следует.
« Последнее редактирование: 09-07-2007 19:21 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #15 : 10-07-2007 05:37 » 

LogRus,
const char * num_txt = "133";
- это глобальная переменная. Не есть хорошо совсем...

>> ну ведь можно написать функцию 
Можно... с кучей передаваемых параметров. Обычно макросы описываю уже внутри функции (там, где много повторяющихся кусков). Иногда действительно пепеделываю в функторы, но иногда это не удобно, так и остаются макросы

Сделай переменную статиком Улыбаюсь ИМХО лучше чем макрос.
Повторяющихся кусков кода, то стараемся его всегда выносить в функции даже, если функция маленькая.

что касается статьи от Михалыча, то там импользование макроопределений рассматривается в основном, как некая замена typedef

Согласен, от макроопределений полностью отказаться нельзя(особенно, если тебе нужен страж хедера Улыбаюсь ), как известно всё лекарство и всё яд

Когда я смело использую макросы:
1. Стражи заголовочных файлов(про #pragma once умолчим Улыбаюсь platform specific)
2. Условная компиляция(для разных платформ или отладка/релиз)
3. Передача в функцию переменной и символьного представления имени переменной/класса
4. Нет дрого пути кроме, как использовать макрос
к пукту 4 пример
Код:
#define LOG_DATA(Name, Condition, OutData) \
            if(Condition) \
            { \
                  std::cout << Name << " Data: " << OutData << "\n"; \
            }
используем это дело:
Код:
int func(string& s, int i, long l, bool dump)
{
        LOG_DATA("FUNC", dump, << s << " " << i << " "<< l);
        ...
}
почему этот код не вынести в функцию? потому, что: тогда всегда буду вынужден выполнять формирование строки OutData
не зависимо от условия, а формирование строки может быть очень дорогой операцией
Но и этот код можно заменить при желании на такой, что строка формироваться не будет без использования, если написть класс обёртку с шаблонным оператором <<
примерно, так
Код:
class Logger
{
    bool dump_;
public:
    Logger(const string& name, bool dump):dump_(dump)
    {
        if (dump)
           std::cout << name << ":"
    }

     template<T>
     Logger& operator<<(const T)
     {
          if(dump_)
          {
                  std::cout << T;
          }
          return *this;
     }
}
теперь испольуем его:
Код:
int func(string& s, int i, long l, bool dump)
{
        {
           Logger log("FUNC", dump);
           log << s << " " << i << " "<< l << "\n";
        }
        ...
}
но у нас появляются дополнительные расходы: конструирование/разрушение объекта, дополнительные вызовы << и проверки условия
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #16 : 10-07-2007 05:44 » 

примерно понятно )

зы кстати, никогда ещё не доводилось пользоваться cout
Записан

Vlaor
Гость
« Ответ #17 : 10-07-2007 15:17 » 

О чем может идти речь, если сама Microsoft в своих include файлах использует эти define направо и налево. Зачем например обьявлять переменную, тратить место в памяти (пусть и мелочи) когда есть стандартный выход. Осторожней просто надо быть. О .
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #18 : 10-07-2007 17:02 » 

Vlaor, константны переменные не расходуют память, а экономят. Если подумаешь, то поймёшь почему.
Что касается MS, так это их личное дело.
Записан

Странно всё это....
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 10-07-2007 17:34 » 

Мое не авторитетное мнение хочу заменить следующим:
Бьерн Страуструп 1997г.
Цитата
Макрос почти всегда указывает на недостаток языка программирования, программы или программиста... Если вы используете макросы, значит, вам не хватает возможностей отладчиков, инструментов, генерирующих перекрестные ссылки, средств профилирования и т.д.

Макконнелл "Соверешенный код" 2изд. стр 180
Цитата
Современные языки вроде С++ поддерживают много альтернатив макросам:
-ключевое слово const для объявления констант;
-ключевое слово inline для определения функций, которые будут компилироваться как встраиваемый код
-шаблоны для безопасного в плане типов определения стандартных операций, таких как min, max и т.д.
-ключевое слово enum для определения перечислений;
-директиву typedef для простых замен одного типа другим
Записан

ещё один вопрос ...
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #20 : 10-07-2007 17:48 » 

а ещё хотелось бы, чтоб у макросов была область видимости )
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #21 : 11-07-2007 04:54 » 

Алексей1153++, направь заявку в комитет по C++ Улыбаюсь
nikedeforest, поддерживаю.
Записан

Странно всё это....
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #22 : 11-07-2007 04:55 » 

LogRus, Улыбаюсь
Записан

Vlaor
Гость
« Ответ #23 : 11-07-2007 16:40 » 

nikedeforest, Я конечно согласен, вот только не пойму насчет экономии памяти. Может тормоз. Ведь при использовании const выделяется место в секции .rdata, но ведь выделяется же. При define происходит прямая подстановка в код.

Например VC6 скомпилил подобный код.
Код:
1:    void func(int);
2:
3:    #define A 10
4:    const int a = 10;
5:
6:    void main()
7:    {

//инициализация

8:    func(A);
0040B468   push        0Ah
0040B46A   call        @ILT+5(func) (0040100a)
0040B46F   add         esp,4
9:    func(a);
0040B472   push        0Ah
0040B474   call        @ILT+5(func) (0040100a)
0040B479   add         esp,4
10:
11:   }

Замечательно, а что мне делать если я хочу использовать нечто вроде:
Код:
#define B (A + 10)
Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 11-07-2007 16:56 » 

> а ещё хотелось бы, чтоб у макросов была область видимости )

#define BLA-BLa-BLA

#undef BLA-BLA-BLA

Ситуация с #define похожа на ситуацию с goto - это было универсальное средство переключения потока управления. Умные люди посидели, подумали, и выделили основные идиомы использования goto в отдельные конструкции - более понятные и безопасные: циклы, прерывания циклов (break, continue), вызовы функций и return. Затем подумали и победили экстремальную форму goto - longjump - ввели исключения.

Также и define - универсальное средство управления кодом. Разработчики С++ приложили массу усилий по созданию заменителей define. Во-первых, замена литералов вида
#define MY_MAGIC_NUMBER 123
на константы
const int my_magic_number = 123
которые можно использовать всюду, где в Си разрешаются только литералы (например, задать размер массива - константы enum в Си для этого недопустимы).
Во-вторых, "маленькие" и "быстрые" функции поддержаны функциями inline.
В-третьих, переиспользование кода для разных типов решено введением шаблонов.

Пожалуй, в Си++ не нашли заменителя для одного сценария использования #define - условной компиляции. Более того, такой сценарий использования макросов перекочевал в С# почти в неизменном виде.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #25 : 11-07-2007 17:01 » 

Vlaor, при использовании const компилятор С++ имеет полное право подставить в точку использования константы её фактическое значение, что полностью эквивалентно константам #define. Если константа статическая (то есть не может использоваться за пределами модуля), то оптимизатор может ее выкинуть из секции данных, расставив во всех местах использования фактическое значение.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #26 : 11-07-2007 17:01 » 

npak, про undef я в курсе. Пользуюсь )
Но стоит поменять имя макроса и забыть поменять его в ундефе - приехали
Записан

npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #27 : 12-07-2007 09:21 » 

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

Я предлагаю в языке С++ использовать макросы только для условной компиляции. Во всех остальных случаях искать решения средствами языка.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #28 : 12-07-2007 09:58 » 

аминь
Записан

ещё один вопрос ...
Scorp__)
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #29 : 10-08-2007 10:56 » 

Да, вот еще особенность макросов съевшая минут 15 времени. Пишу интерфейс под .NET, нужно зарегистрировать горячую клавишу, в этом случае можно воспользоваться только API-шной RegisterHotKey. Отлично, подключаем windows.h. В случае неудачи хочу вывести MessageBox и пользуюсь классом MessageBox для этого, вроде все правильно, пространство имен указал. А компилятор говорит, неа, MessageBoxA() не член этого пространства имен и все тут.

Казалось бы причем тут вообще MessageBoxA(), я его даже не трогаю. Оказывается, в windows.h есть макрос
#define MessageBox MessageBoxA
препроцессор все правильно заменяет, а я сижу и смотрю тупо в монитор пытаясь понять в чем же дело. Решение-то простое:
#undef MessageBox
но все равно неприятно.
Записан

- А Вы сами-то верите в привидения?
- Конечно, нет, - ответил лектор и медленно растаял в воздухе.
Страниц: [1] 2 3  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines