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);, что программисты C хотели бы сделать из-за сходства WARN_IF с функцией; см. Поглощение точки с запятой.
Строкизирование в 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-13.3.0/cpp/Stringizing.html