FeelUs
|
|
« : 08-08-2011 20:47 » |
|
то, что задефайненные идентификаторы (возможно с параметрами) заменяются (раскрываются) соответствующей последовательностью лексем - понятно, вопрос: когда? и в каком порядке? например в строках с директивой #define макросы не раскрываются #define a q #define b a #undef a после такого кода он будет заменять b на a a не на q а например в #if раскрываются после раскрытия макроса в строке он снова ищет идентификаторы, которые можно раскрыть напр. после кода выше, только без undef'a, он будет b заменять на q но тогда непонятно, почему следующий код не заставляет препроцессор зациклиться? #define b a #define a b
int main() { int a; #undef a #undef b a; }
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #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)
|
|
« Ответ #2 : 09-08-2011 05:56 » |
|
IMHO, препроцессор работает в один проход, он не пытается повторно преобразовывать, заменил a на b и погнал дальше что касается конкретного случая #define a q #define b a то для препроцессора это превращается в набор правил a->q b->a->q
когда делаем undef, из цепочки удаляется правило a->q и получаем b->a
далее #define a b #define b a превращается в a->b b->a->b
когда к коду применяются правила, то применяется только одно из, без повторной проверки чего бы еще такого преобразовать (это черевато цилами и провалами производительности) врятли за 40 лет существования языка никто не подумал про зацикливания и максимальную скороть обработки
|
|
|
Записан
|
Странно всё это....
|
|
|
Dale
|
|
« Ответ #3 : 09-08-2011 05:58 » |
|
непонятно, почему следующий код не заставляет препроцессор зациклиться? Курим мануалы. В данном случае: Richard M. Stallman, Zachary Weinberg, "The C Preprocessor For gcc version 4.7.0 (pre-release) (GCC)". Далеко не худший представитель препроцессоров. 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 #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
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #4 : 09-08-2011 06:13 » |
|
На предмет реального зацикливания я не проверял, кстати. Но никогда ничего не зацикливалось - это точно
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #5 : 09-08-2011 06:22 » |
|
IMHO, препроцессор работает в один проход, он не пытается повторно преобразовывать, заменил a на b и погнал дальше ... когда к коду применяются правила, то применяется только одно из, без повторной проверки чего бы еще такого преобразовать (это черевато цилами и провалами производительности) Подстановок на самом деле может быть сколько угодно: #define a b #define b c #define c d #define d "abc" В данном случае a заменяется на "abc". Накладные расходы при этом в сравнении с компиляцией незначительны, ради них не стали урезать функциональность. Исключение делается только в случае зацикливания цепочки. В точке зацикливания макроподстановки прекращаются.
|
|
« Последнее редактирование: 09-08-2011 06:26 от Dale »
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
FeelUs
|
|
« Ответ #6 : 09-08-2011 08:17 » |
|
спасибо за ответы а препроцессор GCC - это интересно, жаль, что не по русски а я вот взял Кернигана и Ричи, Язык рограммирования си, 2-е издание читаю пункт А.12.3, стало понятно почти все, кроме: #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
|
|
« Ответ #7 : 09-08-2011 08:55 » |
|
почему в ходе макроподстановок не появиться cat(1,2)3 или xcat(1,2)3 как препроцессор рассуждает, какой макрос дальше раскрывать? 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
|
|
« Ответ #8 : 09-08-2011 12:02 » |
|
получается примерно такой алгоритм: замена_макросов(список_лексем, Список_Проделанных_Макросов С_П_М) { while(берет самый левый (внешний) макрос (из списка_лексем), не содержащийся в С_П_М ) { раскрывает его; выполняет # с каждым аргументом; выполняет ##; c каждым аргументом или группой_сцепленных_аргументов замена_макросов(этого аргумента или группы_сцепленных_аргументов, С_П_М+текущий_раскрытый_макрос); замена_макросов(результата текущего_раскрытого_макроса, С_П_М+текущий_раскрытый_макрос+все макросы раскрытые во всех рекурсивных вызовах в течении последней итерации цикла) } }
изначально все это дело вызывается с пустым списком проделанных макроссов
еще глядя на эту тему наверно перед циклом выполняется примерно такой же цикл со всеми макросами без параметров, только без рекурсивных вызовов и еще наверно где-то ближе к концу выполняется удаление возникших комментариев скажите, а препроцессор вообще обладает полнотой по Тьюрингу? PS нда, эта глава вкуривается далеко не с первого раза, но пока это самая полная и понятная для меня вещь
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #9 : 09-08-2011 12:23 » |
|
получается примерно такой алгоритм: ... еще глядя на эту тему наверно перед циклом выполняется примерно такой же цикл... ... и еще наверно где-то ближе к концу выполняется удаление возникших комментариев А зачем так много "наверно" и "примерно"? Есть документ на 83 страницы (я его процитировал пару раз, но осталось еще очень много материала помимо этого), в котором предельно четко расписано поведение препроцессора во всех возможных случаях. Достаточно просто скачать и прочитать. Программирование - это раздел прикладной математики, а математика, как известно, наука точная и не любит слов "наверно" и "примерно". скажите, а препроцессор вообще обладает полнотой по Тьюрингу? Сомневаюсь. Как минимум не вижу в нем средств для органицации циклического выполнения процедур и рекурсии. Иначе его давно уже приспособили бы в качестве интерпретатора.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #10 : 09-08-2011 14:14 » |
|
templates в C++ быть может и обладают, по крайней мере глядя на творения Александреску.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
FeelUs
|
|
« Ответ #11 : 10-08-2011 08:29 » |
|
в шаблонах нельзя например имя шаблона в строку превратить
а есть еще чё-нить русскоязычное по препроцессорам?
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #12 : 10-08-2011 08:38 » |
|
Вот здесь: http://lib.custis.ru/M4 есть совсем немного на русском по макропроцессору m4. А вообще рассчитывать на обилие русскоязычной документации уровня выше, чем "для чайников" и "освой за 10 минут", не стоит. Хотите постоянно быть на уровне - читайте оригиналы.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
|
|