3.4 Строкификация
Иногда вам может потребоваться преобразовать аргумент макроса в строковую константу. Параметры не заменяются внутри строковых констант, но вы можете использовать оператор предварительной обработки ‘#’ вместо этого. Когда параметр макроса используется с начальным символом ‘#’, препроцессор заменяет его буквальным текстом фактического аргумента, преобразованного в строковую константу. В отличие от обычной замены параметров, аргумент сначала не раскрывается макросом. Это называется строкификацией.
Нет способа объединить аргумент с окружающим текстом и строкифицировать все вместе. Вместо этого вы можете написать серию смежных строковых констант и строкифицированных аргументов. Препроцессор заменит строкифицированные аргументы строковыми константами. Компилятор C затем объединит все смежные строковые константы в одну длинную строку.
Вот пример определения макроса, использующего строкификацию:
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf (stderr, "Warning: " #EXP "\n"); } \
while (0)
WARN_IF (x == 0);
==> do { if (x == 0)
fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0); Аргумент для EXP заменяется один раз, как есть, в if операторе, и один раз, строкифицированный, в аргументе для fprintf. Если x был макросом, он был бы раскрыт в операторе if, но не в строке.
do и while (0) являются обходным способом, чтобы сделать возможным написание WARN_IF (arg);, что сходство WARN_IF с функцией заставило бы программистов C захотеть это сделать; см. Проглатывание точки с запятой.
Строкификация в C подразумевает больше, чем просто добавление двойных кавычек вокруг фрагмента. Препроцессор экранирует символы обратной косой чертой кавычки, окружающие встроенные строковые константы, и все обратные косые черты внутри строковых и символьных констант, чтобы получить действительную строковую константу C с правильным содержимым. Таким образом, строкификация p = "foo\n"; приводит к "p = \"foo\\n\";". Однако обратные косые черты, которые не находятся внутри строковых или символьных констант, не дублируются: ‘\n’ сама по себе строкифицируется в "\n".
Все начальные и конечные пробелы в строках, подлежащих строкификации, игнорируются. Любая последовательность пробелов посередине текста преобразуется в один пробел в результатах строкификации. Комментарии заменяются пробелами задолго до строкификации, поэтому они никогда не появляются в строкифицированном тексте.
Нет способа преобразовать аргумент макроса в символьную константу.
Если вы хотите строкифицировать результат раскрытия аргумента макроса, вам нужно использовать два уровня макросов.
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
==> "foo"
xstr (foo)
==> xstr (4)
==> str (4)
==> "4" s строкифицируется при использовании в str, поэтому он не раскрывается макросом в первую очередь. Но s — это обычный аргумент для xstr, поэтому он полностью раскрывается макросом до того, как сам xstr раскрывается (см. Предварительный просмотр аргументов). Таким образом, к тому времени, когда str получает свой аргумент, он уже был раскрыт макросом.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/cpp/Stringification.html