Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 52, средняя оценка - 4.90
ertyuo
0 / 0 / 0
Регистрация: 05.01.2010
Сообщений: 9
#1

Чем же макрос define так плох? - C++

08.01.2010, 03:29. Просмотров 7481. Ответов 115

После прочтения про директиву препроцессора define возник вопрос по поводу применения define, как функции:
C++
1
#define QQ (q) (q^q)
Можно же улучшить читаемость кода, используя вместо функций именно директиву define. Или у данного использования макроса есть подводные камки какие-то? Да и объем кода в разы сократиться, так как для define будет достаточно всего-навсего одной строчки.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.01.2010, 03:29
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Чем же макрос define так плох? (C++):

Чем плох make? - C++
Дали написать реферат по make файлам и соответственно указать его минусы, а значит сравнить его с такими утилитами как CMake, но для меня...

Чем плох std::map? - C++
std::map ?

Чем плох void main? - C++
Встретил мнение, что void main() - не канон и даже плохо. Но статья древняя, 1996 года, и даже автор открестился, сказав, что для новых...

Чем плох управляемый С++? - C++
Я дико извиняюсь за подобную тему... но дело в том, что мне сегодня задали этот вопрос и, собственно, я не смог на него ответить. Сам я...

Перевести макрос define в функцию - C++
Доброго времени суток. Я тут на днях набросал вот такие макросы для удобства: #define BinSave(Value, Root)\ //Переменная, путь к...

Чем оличается define от const - C++
define A 5; и const a = 5; В первом случае идет замена в предпроцессоре... а во втором? и еще слышал что define оч редко стал...

115
Evg
Эксперт CАвтор FAQ
18026 / 6258 / 427
Регистрация: 30.03.2009
Сообщений: 17,193
Записей в блоге: 27
24.10.2015, 01:09 #46
Цитата Сообщение от LynXzp Посмотреть сообщение
#define a n это ... зачем
Это моделирование ситуации, когда программист стреляет себе в ногу
1
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 11:38 #47
Цитата Сообщение от Evg Посмотреть сообщение
Гадать нужно. Ибо товарищ не предоставил исходник, и чего он там мерил - непонятно
нет, не нужно.
потому что совершенно не важно:
ни что именно учудил товарищ,
ни что он там себе думает.

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

Цитата Сообщение от Evg Посмотреть сообщение
А что такое адрес константы - я вообще не понимаю. В твоём случае n - это автоматическая переменная, а не константа. Я вообще слабо понимаю, что вы тут придумали на предмет того, выделяется память под константу, или нет. Когда LynXzp об этом говорил, я ещё хоть как-то его понимал, потому что знал, что он на ломанном языке изъясняется (у него были опасения, что лишний define или элемент enum'а попадают в код). Что говоришь ты - я не понимаю вообще ничего
я думал, моя мысля - предельно проста и очевидна.
но на всякий случай оставил пример-иллюстрацию с выдержкой кода
и демонстрацией на онлайн компиляторе.

обратите внимание:
значение константы используется в качестве параметра шаблона.

это возможно только и только в одном случае:
константа времени компиляции.

по поводу адреса константы поясню:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int foo(const size_t*); //<--- реализация "где то там"
   // в другой единице трансляции
   // здесь будет резолвить линкер
 
int main()
{
    const size_t n = 10;
 
    int array[n] = {}; //<--- можно, 
         // n - константа, значение которой известно времени компиляции
 
    // <--- до этого момента память под константу n не выделялась
    // потому что нигде не использовался адрес константы
    // а для того, что бы организовать массив
    // компилятору достаточно сделать inline подстановку значения константы
  
    foo(&n); //<--- а вот теперь мы попросили адрес константы
     //компилятор обязан нам его предоставить
 
     //но что бы это было возможно
     //компилятор вынужден создать реальный объект константы
     //разместив его в памяти, что бы у него появился реальный адрес
     //который мы можем получить
 
     //удалите вызов функции foo,
     //и компилятор не станет выделять память под константу
}
Добавлено через 11 минут
Цитата Сообщение от Evg Посмотреть сообщение
По мне так если есть вопрос на предмет того, что и как попадает в код, то
читаешь стандарт языка.

а вот что там за ассмовыхлоп получится - монопенисуальный фактор,
и геммор компилятора, а не программиста.

вот вам ещё один пример:


C++
1
2
3
4
5
6
struct example
{
    static const int value = 10; // <--- законный способ объявления константы 
           //с бородатых времен
      // но почему?
};
почему стандарт требует объявлять статические члены классов явно в ед. трансляций,
но не требует этого для фундаментальных констант?

потому что не константы, или не фундаментальные типы нужно где то размещать в памяти.
в данном случае в статической.
и нужно знать - где.

но фундаментальные константы память не кушают.
поэтому их можно определить прямо в хэдере.

здесь мы кстати, наблюдаем один из величайших косяков в дизайне языка:
если мы попросим адрес у такой константы, то...
о боже! все будет по прежнему работать, как часики.

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

поэтому, нет никаких технических ограничений,
применить механизм автоматической аллокации статического объекта,
определенного в хэдэре.

то есть, они ещё давным давно могли позволить определять в хэдерах
не только фундаментальные константы,
но и любые другие объекты.

в настоящий же момент ограничение "только для фундаментальных констант"
снято только и только для шаблонов.
2
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
24.10.2015, 13:19 #48
Цитата Сообщение от hoggy Посмотреть сообщение
что под константы не выделяется память,
если не используются их адреса.
Имхо, вы обсуждаете разные вещи с разных позиций. Т.к. если значение (не адрес) этой константы используется, она явно или косвенно попадет в сегмент данных или кода, что повлияет на размер объектного файла.
Цитата Сообщение от hoggy Посмотреть сообщение
но не требует этого для фундаментальных констант?
Интегральных, а не фундаментальных. Для неинтегральных типов нужно добавлять constexpr.
1
Evg
Эксперт CАвтор FAQ
18026 / 6258 / 427
Регистрация: 30.03.2009
Сообщений: 17,193
Записей в блоге: 27
24.10.2015, 13:45 #49
Из всего твоего большого текста я понял, что словом "константа" ты называешь "переменную с квалификатором const". Хотя LynXzp изначально поднимал вопрос о define и enum'ах. В общем классический для форумов вариант, когда спрашивают о том, как нарисовать зелёный круг, а отвечают про то, как варить суп, и при этом кастрюлю называют словом "паровоз"

Добавлено через 13 минут
Хотя вполне возможно, что это я неправильно понял фразу "А константы это издевательство, они же будут занимать память все вне зависимости от использования" и LynXzp тоже называет "константой" переменную с квалифиатором const. Тогда согласен - я неправильно понял вас обоих. Но здесь я руководствуюсь стандартным принципом - я всегда исхожу из того, что новичок может изъясняться корявым языком, но знающий человек обычно называет вещи своими именами

Добавлено через 4 минуты
Цитата Сообщение от Evg Посмотреть сообщение
Ушёл в игнор
В виду вышенаписанного удалил из игнора. Прошу прощения

Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
А не о том, что используемые константы/массивы кушают память
Я тебе всего лишь продемонстрировал на конкретном примере, что нельзя делать никаких выводов, опираясь на размер результирующего бинарника. И конкретный пример вполне наглядно показывал - две программы с разным размером массива имеют одинаковый размер бинарника. Именно из-за выравнивания секций, о которых я писал ранее
1
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 14:01 #50
Цитата Сообщение от Tulosba Посмотреть сообщение
она явно или косвенно попадет в сегмент данных или кода, что повлияет на размер объектного файла.
нет, не попадет.

потому что формально она вообще не будет существовать,
пока вы не попросите её адрес.
Цитата Сообщение от Tulosba Посмотреть сообщение
Интегральных, а не фундаментальных.
нет, фундаментальных.

например,
float не является интегральным,
однако для него это так же срабатывает.

Цитата Сообщение от Evg Посмотреть сообщение
что словом "константа" ты называешь "переменную с квалификатором const"
Ага.
константой я называю объект рожденный константным.
1
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
24.10.2015, 14:25 #51
Цитата Сообщение от hoggy Посмотреть сообщение
потому что формально она вообще не будет существовать,
C++
1
2
3
4
5
#include <cstdio>
 
int main() {
    printf( "%d\n", 42 );
}
Т.е. программа выводит число, и при этом оно нигде не хранится и ничего не занимает? Откуда же оно появляется на консоли?
Цитата Сообщение от hoggy Посмотреть сообщение
float не является интегральным,
однако для него это так же срабатывает.
Срабатывает что? Я рассматривал твой пример:
C++
1
2
3
4
struct example
{
    static const int value = 10; 
};
Если здесь будет не интегральный тип (например double), то нужно явно добавлять определение переменной или добавлять constexpr. Пример.
1
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 14:30 #52
Цитата Сообщение от Tulosba Посмотреть сообщение
Т.е. программа выводит число, и при этом оно нигде не хранится и ничего не занимает? Откуда же оно появляется на консоли?
ага.

компилятору пофигу:

C++
1
2
3
4
int main()
{
    cout<< 10;
}
или
C++
1
2
3
4
5
int main()
{
    const int v  = 10;
    cout<< v;
}


Цитата Сообщение от Tulosba Посмотреть сообщение
Срабатывает что? Я рассматривал твой пример:
замените мой пример на:

C++
1
2
3
4
struct example
{
    static const float value = 10.5f; 
};
получите тоже самое поведение.


замените на шаблон от T
и получите тоже самое поведение для T.
(правда синтаксис будет иным, но не суть)
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
24.10.2015, 14:34 #53
Цитата Сообщение от hoggy Посмотреть сообщение
получите тоже самое поведение.
Я же ссылку привел. Ты не смотрел что ли?
Цитата Сообщение от hoggy Посмотреть сообщение
ага.
Ну, если "ага", то объясни из какого такого "ничто" берется это число. Я послушаю
1
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 14:40 #54
Цитата Сообщение от Tulosba Посмотреть сообщение
Я же ссылку привел. Ты не смотрел что ли?
она не открылась.

Цитата Сообщение от Tulosba Посмотреть сообщение
Ну, если "ага", то объясни из какого такого "ничто" берется это число. Я послушаю
не распарсил этот поток сознания.
0
Evg
Эксперт CАвтор FAQ
18026 / 6258 / 427
Регистрация: 30.03.2009
Сообщений: 17,193
Записей в блоге: 27
24.10.2015, 14:42 #55
Цитата Сообщение от hoggy Посмотреть сообщение
читаешь стандарт языка
Стандарт языка описывает поведение программы, а вовсе не способы, которыми компилятор добивается такого поведения

C++
const int a = 10;
int foo (void) { return a; }
Код
$ g++ t.cc -S
$ cat t.s
...
__Z3foov:
...
        movl    $10, %eax    <--- в точку "return a" компилятор подставил 10
...
        .section .rdata,"dr"
        .align 4
__ZL1a:
        .long   10   <--- но переменная никуда не делась
...
И лишь в режиме с оптимизациями компилятор удалит переменную "a" (т.к. все её использования были заменены на значение константы). Тот факт, что в точку "return a" компилятор подставил значение - это тоже оптимизация, просто у современных компиляторов даже в режиме без оптимизаций делаются некоторые точечные оптимизации, которые практически не увеличивают время компиляции

Можно копнуть дальше и подать этот же код на вход компилятора Си (переименовав t.cc в t.c). И мы увидим, что в этом случае даже в режиме с оптимизациями переменная НЕ была удалена. Почему так происходит? Да потому что эти два кода (один и тот же текст в режимах Си и Си++) НЕ эквивалентны. В режиме Си++ на глобальные переменные с квалификатором const неявно навешивается модификатор static. И эквивалентный код на Си должен выглядеть как

C
static const int a = 10;
int foo (void) { return a; }
Тогда мы увидим симметричный код и симметричное поведение компилятора (в режиме без оптимизаций переменная остаётся, с оптимизациями удаляется)
0
Tulosba
:)
Эксперт С++
4396 / 3232 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
24.10.2015, 14:47 #56
Цитата Сообщение от hoggy Посмотреть сообщение
она не открылась.
Цитата Сообщение от hoggy Посмотреть сообщение
не распарсил этот поток сознания.
Ну попробуй ещё раз почитать и ссылку понажимать, может поймешь. Если всё-таки не справишься за обозримое время, изложу подробнее.

Добавлено через 3 минуты
Цитата Сообщение от Evg Посмотреть сообщение
И эквивалентный код на Си должен выглядеть как
Вот чего тут не стоит делать, так это сишный код приплетать. Всё-таки в разделе плюсов обсуждение идет.
0
Evg
Эксперт CАвтор FAQ
18026 / 6258 / 427
Регистрация: 30.03.2009
Сообщений: 17,193
Записей в блоге: 27
24.10.2015, 14:50 #57
Цитата Сообщение от Tulosba Посмотреть сообщение
Вот чего тут не стоит делать, так это сишный код приплетать. Всё-таки в разделе плюсов обсуждение идет
Обсуждается не язык, а код, получаемый компилятором. И эквивалентные конструкции Си куда более очевидны для понимания того, как строится код
0
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 16:27 #58
Цитата Сообщение от Evg Посмотреть сообщение
Стандарт языка описывает поведение программы, а вовсе не способы, которыми компилятор добивается такого поведения
оке.

в дебаге компилятор может и не выпиливать промежуточные значения.


ну и?

Добавлено через 3 минуты
Цитата Сообщение от Evg Посмотреть сообщение
Обсуждается не язык, а код, получаемый компилятором.
обсуждается именно язык.

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

есть исключение - конструкторы копии, либо r-value конструкторы.
эти компилятор может оптимизировать невзирая на их возможные эффекты.

Добавлено через 3 минуты
Цитата Сообщение от Tulosba Посмотреть сообщение
Ну попробуй ещё раз почитать и ссылку понажимать, может поймешь.
блиа:
Цитата Сообщение от hoggy Посмотреть сообщение
она не открылась.
сколько раз нужно тыкать, что бы понять?

Цитата Сообщение от Tulosba Посмотреть сообщение
Если всё-таки не справишься за обозримое время, изложу подробнее.
время пришло.
0
Evg
Эксперт CАвтор FAQ
18026 / 6258 / 427
Регистрация: 30.03.2009
Сообщений: 17,193
Записей в блоге: 27
24.10.2015, 16:34 #59
Цитата Сообщение от hoggy Посмотреть сообщение
ну и?
А не надо делать выводов о том, где и как расходуется память, опираясь на стандарт языка и на какие-то высосанные из пальца доводы. Особенно если вдруг под микроконтроллер нет полноценного оптимизирующего компилятора

Цитата Сообщение от hoggy Посмотреть сообщение
по стандарту компиляторы могут выполнять любые оптимиации
Вот именно, что "могут", а тебя послушать, так они "обязаны", а не "могут"
1
hoggy
6672 / 2856 / 491
Регистрация: 15.11.2014
Сообщений: 6,364
Завершенные тесты: 1
24.10.2015, 16:50 #60
Цитата Сообщение от Evg Посмотреть сообщение
А не надо делать выводов о том, где и как расходуется память, опираясь на стандарт языка и на какие-то высосанные из пальца доводы. Особенно если вдруг под микроконтроллер нет полноценного оптимизирующего компилятора
я и неделаю.
Цитата Сообщение от Evg Посмотреть сообщение
Вот именно, что "могут", а тебя послушать, так они "обязаны", а не "могут"
компиляторы пишут здравомыслщие люди.
1.
на каких нибудь микроволноффках особенно критично не делать избыточных объектов.

2.
мой пример кода выше написан согласно стандатру.
а из этого следует, что любой копилятор обязан уметь делать inline подстановку
по месту использования фундаментальной константы.

итого:
все топовые компиляторы умеют оптимизировать промежуточные значение.

компиляторы для микроволновок - и подавно это умеют.
0
24.10.2015, 16:50
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.10.2015, 16:50
Привет! Вот еще темы с ответами:

#define работает не так, как ожидается - C++
Здравствуйте. Подскажите, пожалуйста, почему в таком случае некорректно использовать #define: switch (kind) { case 1: ...

#define sqr(a) (a)*(a) - зачем так много скобок? - C++
#define sqr(a) ((a)*(a)) такие вопросы: 1) Зачем ((a)*(a)) так много скобок? (если можно,объяснить доступным языком) 2) почему,...

Объясните, в чем суть директив #ifndef/#define/#endif - C++
Не понял в чем суть директив: #ifndef .. #define.. #endifОбъясните пожалуйста..это как - то связано с хедерами, но вот как ??

Что это за макрос? И с чем его едят? - C++
Есть две строки. С первой вроде разобрался, поправьте если не совсем. Из книги Лафоре ООП (реализация консольной графики). #ifndef...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru