Подтвердить что ты не робот

Stringification - как это работает?

Я знаю, что:

#define foo 4  
#define str(s) #s

с str(foo) выписывает: "foo", потому что stringify выполняется сначала из расширения текста, но это:

 #define xstr(s) str(s)
 #define str(s) #s
 #define foo 4

с xstr(foo) выписывает: "4".

Почему? Каковы шаги, участвующие в этом процессе?

4b9b3361

Ответ 1

Соответствующие шаги расширения макросов (за C 2011 [n1570] 6.10.3.1 и С++ 1998 16.3.1):

  • Имена процессов, которым предшествуют # или ##.
  • Применить макрос к каждому аргументу.
  • Замените каждый параметр соответствующим результатом вышеупомянутой замены макроса.
  • Повторно сканировать дополнительные макросы.

Таким образом, при xstr(foo) имеем:

  • Текст замены str(s) не содержит # или ##, поэтому ничего не происходит.
  • Аргумент foo заменяется на 4, поэтому он используется как xstr(4).
  • В тексте замены str(s) параметр s заменяется на 4, создавая str(4).
  • str(4) выполняется повторно. (Полученные шаги производят "4".)

Обратите внимание, что проблема с str(foo) заключается в том, что шаг 2, который заменит foo на 4, появится после шага 1, который изменяет аргумент на строку. На шаге 1 foo все еще foo; он не был заменен на 4, поэтому результат "foo".

Вот почему используется вспомогательный макрос. Это позволяет нам выполнить шаг 2, а затем использовать другой макрос для выполнения шага 1.

Ответ 2

Первый случай

  • Оцените str(foo): замените str(foo) на #foo, т.е. "foo"

Второй случай

  • Оцените xstr(foo): замените xstr(foo) на str(<foo-value>), т.е. str(4)
  • Оцените str(4): замените str(4) на #4, т.е. "4"

Вообще,

Препроцессор

оценивает макро-функции, расширяющие макропеременные, пока не будет ничего, чтобы оценить:

Если вы определяете

#define xstr(s) str(s) + 1
#define str(s) s + 1

в следующем коде

#define foo 4

int main()
{
    std::cout << str(foo) << '\n' 
              << xstr(foo) << '\n' ;

} 

он оценил бы как

Первая строка

  • Замените str(foo) на <foo-value> + 1, т.е. 4 + 1
  • Больше ничего не заменишь. Отделка.

И результат 4 + 1

Вторая строка

  • Замените xstr(foo) на str(<foo-value>) + 1, т.е. str(4) + 1
  • Замените str(4) на <4-value> + 1, т.е. 4 + 1
  • Ничего более, чтобы заменить.

И результат 4 + 1 + 1