Как, собственно, работает трюк с двойной строкой?

По крайней мере некоторые препроцессоры 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?
Если да, то как C99 гарантирует это?
Если нет, то в какой момент поведение переходит от C-определенного к GCC-определенному?

Ответ 1

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

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

6.10.3.1/1:

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

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

Ответ 2

Как отмечает Стив, это гарантируется, и он был гарантирован с момента стандартизации C89 - это был стандарт, кодифицированный операторами # и ## в макросах и мандаты, рекурсивно расширяющие макросы в args, прежде чем подставлять их в тело if и только если тело не применяет аргумент # или ##. C99 в этом отношении не изменяется от C89.