Как препроцессор C обрабатывает круговые зависимости?

Я хочу знать, как препроцессор C обрабатывает круговые зависимости (от #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).

Ответ 1

Пока макрос препроцессора расширяется, это имя макроса не расширяется. Таким образом, все три символа определяются как сами:

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/Если имя заменяемого макроса найдено во время этого сканирования списка замещения (не считая остальных токенов предварительной обработки исходных файлов), он не заменяется. Кроме того, если какие-либо вложенные замены встречают имя заменяемого макроса, оно не заменяется & hellip;

Далее в статье говорится, что любой токен, который не заменен из-за рекурсивного вызова, фактически "заморожен": он никогда не будет заменен:

& hellip; Эти неперемещаемые маркеры предварительной обработки макросов больше не доступны для дальнейшей замены, даже если они были позже (повторно) рассмотрены в контекстах, в которых этот токен предварительной обработки имени макроса в противном случае был бы заменен.

Ситуация, на которую ссылается последнее предложение, редко возникает на практике, но вот простейший случай, о котором я мог подумать:

#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, был заморожен, поэтому он больше не расширяется.

Ответ 2

На ваш вопрос отвечает публикация ISO/IEC 9899: TC2 раздел 6.10.3.4 "Повторное сканирование и дальнейшая замена", пункт 2, который я цитирую здесь для вашего удобства; в будущем , пожалуйста, подумайте о том, чтобы прочитать спецификацию, когда у вас есть вопрос о спецификации.

Если имя заменяемого макроса найдено во время этого сканирования списка замены (не считая остальных токенов предварительной обработки исходных файлов), он не заменяется. Кроме того, если какие-либо вложенные замены встречают имя заменяемого макроса, он не заменяется. Эти неперемещаемые маркеры предварительной обработки макросов больше не доступны для дальнейшей замены, даже если они позже (повторно) рассматриваются в контекстах, в которых этот токен предварительной обработки имени макроса в противном случае был бы заменен.

Ответ 3

https://gcc.gnu.org/onlinedocs/cpp/Self-Referential-Macros.html#Self-Referential-Macros отвечает на вопрос о самореферентных макросах.

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

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

Ответ 4

В вашем примере вы выполняете макрообработку перед определением переменные с тем же именем, поэтому независимо от результата обработки макросов, вы всегда печатаете 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);

Ответ 5

Здесь хорошая демонстрация поведения, описанного в ответах rici's и Эрика Липперта, то есть макроса имя не разворачивается, если оно встречается снова, уже расширяя тот же макрос.

Содержимое 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
};

(я бы опубликовал это как комментарий, но в том числе существенные блоки кода в комментариях выглядел неловко, поэтому вместо этого сделаю это ответом Wiki сообщества. Если вы считаете, что лучше включить его в качестве части существующий ответ, не стесняйтесь его скопировать и попросите удалить эту версию CW.)