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-7.5.0/cpp/Stringizing.html