Как препроцессор 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 63

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.)