Неоднозначность предварительной обработки в C / C ++ - PullRequest
2 голосов
/ 30 ноября 2011

При выполнении следующего кода с использованием «Набор макроопределений 1» я сталкиваюсь с ошибкой «C2065:« С1 »: необъявленный идентификатор».

При использовании «Набор макроопределений 2» код запускается вдать вывод 2.

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

#include <iostream>

// Macro Definitions Set 1
#define A       1
#define D(n)    B(n)
#define B(n)    C##n
#define CA      2

// Macro Definitions Set 2
//#define A     1
//#define D(n)  C##n
//#define CA        2

int main ()
{

    printf ("%d", D(A));
}

Ответы [ 3 ]

3 голосов
/ 30 ноября 2011

Параметр макроса заменяется, если он не находится до или после ## или после #.

Так, в наборе 1 D(A) становится B(1) после замены D(n), чтозаменяется на C1 после повторного сканирования.

В наборе 2 D(A) становится CA, где A не заменяется, как после ##, а CA становится 2после повторного сканирования.

2 голосов
/ 30 ноября 2011

С вашим первым набором макросов:

#define A       1
#define D(n)    B(n)
#define B(n)    C##n
#define CA      2

D(A) оценивается путем выполнения замены макроса на A и последующей подстановки его в список замены для D(n). В результате замены макроса получается 1, поэтому получается B(1). B(1) затем рекурсивно оценивается, давая C##1, который объединяется с токеном предварительной обработки C1.

С вашим вторым набором макросов:

#define A     1
#define D(n)  C##n
#define CA    2

Когда вычисляется D(A), замена макроса для аргумента n выполняется , а не , потому что перед ним стоит ##. Это дает C##A, что приводит к токену предварительной обработки CA. Затем он повторно проверяется на наличие макросов для замены, что приводит к 2.

0 голосов
/ 30 ноября 2011

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

Теперь, что происходит с использованием набора 2:

  • printf("%d", D(A)); <- первый найденный токен препроцессора <code>D(A), поэтому:
  • printf("%d", CA);
  • printf("%d", 2);

То, что происходит с сетом 1:

  • printf("%d", D(A)); <- первый найденный токен препроцессора <code>D(A), поэтому:
  • printf("%d", B(A)); <- теперь следующий найденный токен <code>A
  • printf("%d", B(1));
  • printf("%d", C1); <- и ошибка </li>

Проблема в том, что происходит замена, тогда препроцессор находит следующий A (возможно, не перезапускает строку) и выполняет другую замену. Затем он снова проходит через это, но находит B(1).

Чтобы проверить это, вы можете просто пропустить некоторые из последующих объявлений и выполнить предварительную обработку в файл. Это покажет вам точно, что происходит.

...