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

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

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

« : 08-08-2011 20:47 » 

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

например в строках с директивой #define макросы не раскрываются
Код: (C++)
#define a q
#define b a
#undef a
после такого кода он будет заменять b на a a не на q
а например в #if раскрываются

после раскрытия макроса в строке он снова ищет идентификаторы, которые можно раскрыть
напр. после кода выше, только без undef'a, он будет b заменять на q

но тогда непонятно, почему следующий код не заставляет препроцессор зациклиться?
Код: (C++)
#define b a
#define a b

int main()
{
        int a;
#undef a
#undef b
        a;
}
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

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


WWW
« Ответ #1 : 09-08-2011 03:33 » 

#define a q //определили  a->q
#undef a //забыли определение

#define b a //определили  b->a

>>после такого кода он будет заменять b на a a не на q
да Улыбаюсь
содержимое макросов до момента их подстановки совершенно неважно. Тут успели разопределить макрос, поэтому a больше не заменяется на q


>>но тогда непонятно, почему следующий код не заставляет препроцессор зациклиться?
рекурсия потому что

#define b a
#define a b

написано : int a;
раскрывается: int b;  
раскрывается: int a;  
раскрывается: int b;  
...


из этого золотые правила:
1) как можно меньше пользоваться макросами (это действительно бывает нужно оооочень редко)
2) стараться размещать макросы в cpp файле после всех директив #include
3) если пришлось применить макрос, задавать ему длинное понятное имя
« Последнее редактирование: 09-08-2011 03:37 от Алексей1153++ » Записан

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

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


WWW
« Ответ #2 : 09-08-2011 05:56 » 

IMHO, препроцессор работает в один проход, он не пытается повторно преобразовывать, заменил a на b и погнал дальше

что касается конкретного случая
Код: (C)
#define a q
#define b a
то для препроцессора это превращается в набор правил
Код:
a->q
b->a->q
когда делаем undef, из цепочки удаляется правило a->q и получаем
Код:
b->a

далее
Код: (C)
#define a b
#define b a
превращается в
Код:
a->b
b->a->b
когда к коду применяются правила, то применяется только одно из, без повторной проверки чего бы еще такого преобразовать (это черевато цилами и провалами производительности)
врятли за 40 лет существования языка никто не подумал про зацикливания и максимальную скороть обработки
Записан

Странно всё это....
Dale
Блюзмен
Команда клуба

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

WWW
« Ответ #3 : 09-08-2011 05:58 » 

непонятно, почему следующий код не заставляет препроцессор зациклиться?

Курим мануалы. В данном случае: Richard M. Stallman, Zachary Weinberg, "The C Preprocessor For gcc version 4.7.0 (pre-release) (GCC)". Далеко не худший представитель препроцессоров.

Цитата
3.10.5 Self-Referential Macros.

A self-referential macro is one whose name appears in its definition. Recall that all macro definitions are rescanned for more macros to replace. If the self-reference were considered a use of the macro, it would produce an infinitely large expansion. To prevent this, the self-reference is not considered a macro call. It is passed into the preprocessor output unchanged.
И далее:
Цитата
If a macro x expands to use a macro y, and the expansion of y refers to the macro x, that is an indirect self-reference of x. x is not expanded in this case either. Thus, if we have
Код: (C)
#define x (4 + y)
#define y (2 * x)
then x and y expand as follows:

x -> (4 + y)
  -> (4 + (2 * x))

y -> (2 * x)
  -> (2 * (4 + y))


Each macro is expanded when it appears in the definition of the other macro, but not when it indirectly appears in its own definition.

Как видите, никакого зацикливания не может быть по определению.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Алексей++
глобальный и пушистый
Глобальный модератор

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


WWW
« Ответ #4 : 09-08-2011 06:13 » 

На предмет реального зацикливания я не проверял, кстати. Но никогда ничего не зацикливалось - это точно
Записан

Dale
Блюзмен
Команда клуба

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

WWW
« Ответ #5 : 09-08-2011 06:22 » 

IMHO, препроцессор работает в один проход, он не пытается повторно преобразовывать, заменил a на b и погнал дальше
...
когда к коду применяются правила, то применяется только одно из, без повторной проверки чего бы еще такого преобразовать (это черевато цилами и провалами производительности)

Подстановок на самом деле может быть сколько угодно:

Код: (C)
#define a b
#define b c
#define c d
#define d "abc"

В данном случае a заменяется на "abc".

Накладные расходы при этом в сравнении с компиляцией незначительны, ради них не стали урезать функциональность. Исключение делается только в случае зацикливания цепочки. В точке зацикливания макроподстановки прекращаются.
« Последнее редактирование: 09-08-2011 06:26 от Dale » Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
FeelUs
Участник

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

« Ответ #6 : 09-08-2011 08:17 » 

спасибо за ответы
а препроцессор GCC - это интересно, жаль, что не по русски
а я вот взял Кернигана и Ричи, Язык рограммирования си, 2-е издание
читаю пункт А.12.3, стало понятно почти все, кроме:
Код: (C++)
#define cat(x,y) x##y
#define xcat(x,y) cat(x,y)

xcat(xcat(1,2),3)
почему в ходе макроподстановок не появиться cat(1,2)3 или xcat(1,2)3
как препроцессор рассуждает, какой макрос дальше раскрывать?
Записан
Dale
Блюзмен
Команда клуба

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

WWW
« Ответ #7 : 09-08-2011 08:55 » 

почему в ходе макроподстановок не появиться cat(1,2)3 или xcat(1,2)3
как препроцессор рассуждает, какой макрос дальше раскрывать?

Цитата
3.10.6 Argument Prescan

Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.

При раскрытии xcat(xcat(1, 2), 3) сначала, как полагается, производится прескан аргументов. Раскрывается первый аргумент:
xcat(1, 2) -> cat(1, 2) -> 12.
Прескан второго аргумента дает результат 3.

Теперь раскрывается сам макрос:
xcat(12, 3) -> cat(12, 3) -> 123.

P.S. По-моему, понять работу с макросами по Кернигану и Ричи - это подвиг, более невразумительной главы во всей книге не сыскать.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
FeelUs
Участник

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

« Ответ #8 : 09-08-2011 12:02 » 

получается примерно такой алгоритм:
Код:
замена_макросов(список_лексем, Список_Проделанных_Макросов С_П_М)
{
    while(берет самый левый (внешний) макрос (из списка_лексем), не содержащийся в С_П_М )
    {
        раскрывает его;
        выполняет # с каждым аргументом;
        выполняет ##;
        c каждым аргументом или группой_сцепленных_аргументов
            замена_макросов(этого аргумента или группы_сцепленных_аргументов, С_П_М+текущий_раскрытый_макрос);
        замена_макросов(результата текущего_раскрытого_макроса, С_П_М+текущий_раскрытый_макрос+все макросы раскрытые во всех рекурсивных вызовах в течении последней итерации цикла)
    }
}

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

скажите, а препроцессор вообще обладает полнотой по Тьюрингу?

PS нда, эта глава вкуривается далеко не с первого раза, но пока это самая полная и понятная для меня вещь
Записан
Dale
Блюзмен
Команда клуба

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

WWW
« Ответ #9 : 09-08-2011 12:23 » 

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

А зачем так много "наверно" и "примерно"? Есть документ на 83 страницы (я его процитировал пару раз, но осталось еще очень много материала помимо этого), в котором предельно четко расписано поведение препроцессора во всех возможных случаях. Достаточно просто скачать и прочитать.

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

скажите, а препроцессор вообще обладает полнотой по Тьюрингу?

Сомневаюсь. Как минимум не вижу в нем средств для органицации циклического выполнения процедур и рекурсии. Иначе его давно уже приспособили бы в качестве интерпретатора.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

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

« Ответ #10 : 09-08-2011 14:14 » 

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

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
FeelUs
Участник

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

« Ответ #11 : 10-08-2011 08:29 » 

в шаблонах нельзя например имя шаблона в строку превратить

а есть еще чё-нить русскоязычное по препроцессорам?
Записан
Dale
Блюзмен
Команда клуба

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

WWW
« Ответ #12 : 10-08-2011 08:38 » 

Вот здесь: http://lib.custis.ru/M4 есть совсем немного на русском по макропроцессору m4.

А вообще рассчитывать на обилие русскоязычной документации уровня выше, чем "для чайников" и "освой за 10 минут", не стоит. Хотите постоянно быть на уровне - читайте оригиналы.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
PredatorAlpha
Помогающий

ua
Offline Offline

« Ответ #13 : 11-08-2011 12:39 » 

Насчёт # и ## в макросах:
http://www.rsdn.ru/forum/cpp/253468.1.aspx
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines