Стрификация - как это работает?
Я знаю это:
#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"
,
Зачем? Какие шаги участвуют в процессе?
2 ответа
Соответствующие шаги расширения макроса (в соответствии с C 2011 [n1570] 6.10.3.1 и C++ 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.
Первый случай
- оценивать
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