Как именно работает трюк с двумя строками? - PullRequest
81 голосов
/ 02 мая 2010

По крайней мере, некоторые препроцессоры C позволяют вам преобразовывать значение макроса вместо его имени, передавая его через один функциональный макрос другому, который его преобразует в строку:

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */

Примеры использования здесь .

Это работает, по крайней мере, в GCC и Clang (оба с -std=c99), но я не уверен , как работает в терминах стандарта C.

Это поведение гарантировано C99?
Если да, то как С99 это гарантирует?
Если нет, то в какой момент поведение переходит от определенного C к определенному GCC?

Ответы [ 2 ]

75 голосов
/ 02 мая 2010

Да, это гарантировано.

Это работает, потому что аргументы макросов сами по себе развернуты макрокомандой, за исключением , где имя аргумента макроса появляется в теле макроса со строковым модификатором # или token-paster ##.

6.10.3.1 / 1:

... После аргументов для вызов функционального макроса были определены, аргумент замена происходит. Параметр в списке замены, если предшествует # или ## предварительная обработка токен или ## токен предварительной обработки (см. ниже) заменено соответствующим аргументом после того, как все содержащиеся в нем макросы были расширены ...

Итак, если вы сделаете STR1(THE_ANSWER), вы получите «THE_ANSWER», потому что аргумент STR1 не раскрывается макросом. Однако аргумент STR2 является макроразвернутым, когда он подставляется в определение STR2, что, следовательно, дает STR1 аргумент 42 с результатом "42".

19 голосов
/ 02 мая 2010

Как отмечает Стив, это гарантировано и гарантировано начиная со стандарта C89 - это был стандарт, кодифицировавший операторы # и ## в макросах и мандатах рекурсивное расширение макросов в аргументах перед их заменой в теле, если и только если тело не применяет # или ## к аргументу. В этом отношении С99 не отличается от С89.

...