Как препроцессор C обрабатывает циклические зависимости?
Я хочу знать, как C препроцессор обрабатывает циклические зависимости (of #defines). Это моя программа:
#define ONE TWO
#define TWO THREE
#define THREE ONE
int main()
{
int ONE, TWO, THREE;
ONE = 1;
TWO = 2;
THREE = 3;
printf ("ONE, TWO, THREE = %d, %d, %d n",ONE, TWO, THREE);
}
вот вывод препроцессора. Я не могу понять, почему выход как таковой. Я хотел бы знать различные шаги, которые препроцессор принимает в этом случае, чтобы дать следующий результат.
# 1 "check_macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "check_macro.c"
int main()
{
int ONE, TWO, THREE;
ONE = 1;
TWO = 2;
THREE = 3;
printf ("ONE, TWO, THREE = %d, %d, %d n",ONE, TWO, THREE);
}
Я запускаю эту программу на linux 3.2.0-49-generic-pae и компилирую в gcc версии 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5).
5 ответов:
в то время как макрос препроцессора расширяется, имя этого макроса не расширяется. Таким образом, все три ваших символа определяются как они сами:
ONE -> TWO -> THREE -> ONE (not expanded because expansion of ONE is in progress) TWO -> THREE -> ONE -> TWO ( " TWO " ) THREE -> ONE -> TWO -> THREE ( " THREE " )
это поведение устанавливается §6.10.3.4 стандарта C (номер раздела из проекта C11, хотя, насколько мне известно, формулировка и нумерация раздела не изменились с C89). При обнаружении имени макроса оно заменяется его определением (и
#
и##
операторы препроцессора рассматриваются, как а также параметры для функциональных макросов). Затем результат повторно сканируется для большего количества макросов (в контексте остальной части файла):2/ Если имя заменяемого макроса найдено во время сканирования списка замен (не включая остальные маркеры предварительной обработки исходного файла), он не заменяется. Кроме того, если какие-либо вложенные замены сталкиваются с именем заменяемого макроса, он не заменяется...
пункт идет чтобы сказать, что любой токен, который не заменяется из-за рекурсивного вызова, фактически "заморожен": он никогда не будет заменен:
... эти несмещенные маркеры предварительной обработки имени макроса больше не доступны для дальнейшей замены, даже если они позже (повторно)рассматриваются в контекстах, в которых этот маркер предварительной обработки имени макроса в противном случае был бы заменен.
ситуация, о которой говорится в последнем предложении, редко возникает на практике, но вот самый простой случай, который я мог придумать:
#define two one,two #define a(x) b(x) #define b(x,y) x,y a(two)
результат
one, two
.two
увеличивается доone,two
во время заменыa
, и расширеннуюtwo
помечается как полностью расширен. Впоследствии,b(one,two)
расширяется. Это уже не в контексте заменыtwo
, аtwo
который является вторым аргументомb
был заморожен, поэтому он не расширяется.
на ваш вопрос отвечает публикация ISO / IEC 9899: TC2 раздел 6.10.3.4 "повторное сканирование и дальнейшая замена", пункт 2, который я цитирую здесь для вашего удобства; в будущем пожалуйста, рассмотрите возможность чтения specificaftion, когда у вас есть вопрос о спецификации.
Если имя заменяемого макроса найдено во время этого сканирования списка замен (не включая остальную часть предварительной обработки исходного файла токены), он не заменяется. Кроме того, если какие-либо вложенные замены встречаются с именем заменяемого макроса, он не заменяется. Эти несмещенные маркеры предварительной обработки имен макросов больше не используются доступны для дальнейшей замены, даже если они позже (повторно)рассматриваются в контекстах, в которых в противном случае этот маркер предварительной обработки имени макроса был бы заменен.
https://gcc.gnu.org/onlinedocs/cpp/Self-Referential-Macros.html#Self-Referential-Macros отвечает на вопрос о самореферентных макросах.
суть ответа заключается в том, что когда препроцессор находит самореферентные макросы, он их вообще не расширяет.
Я подозреваю, что та же логика используется для предотвращения расширения круговых макросов. В противном случае препроцессор будет находиться в бесконечном расширении.
в вашем примере вы выполняете обработку макросов перед определением переменные с одинаковыми именами, поэтому независимо от того, какой результат из макро обработки, вы всегда печатаете
1, 2, 3
!вот пример, где переменных определяются в первую очередь:
#include <stdio.h> int main() { int A = 1, B = 2, C = 3; #define A B #define B C //#define C A printf("%d\n", A); printf("%d\n", B); printf("%d\n", C); }
это выводит
3 3 3
. Несколько коварно, без комментариев#define C A
изменяет поведение линииprintf("%d\n", B);
вот хорошая демонстрация поведения, описанного в хотим заметить, что это и Эрика Липперта ответы, т. е. что имя макроса не будет повторно расширено, если оно встречается снова, уже расширяя тот же макрос.
контент
test.c
:#define ONE 1, TWO #define TWO 2, THREE #define THREE 3, ONE int foo[] = { ONE, TWO, THREE };
выход
gcc -E test.c
(исключая начальный# 1 ...
строки):int foo[] = { 1, 2, 3, ONE, 2, 3, 1, TWO, 3, 1, 2, THREE };
(я бы разместил это как комментарий, но включение существенных блоков кода в комментарии-это своего рода неловко, так что я делаю это сообщество Вики ответ вместо этого. Если вы считаете, что это было бы лучше включить в качестве части существующего ответа, не стесняйтесь копировать его и попросить меня удалить эту версию CW.)