C/C++ конкатенация строк макросов

#define STR1      "s"
#define STR2      "1"
#define STR3      STR1 ## STR2

Можно ли конкатенатировать STR3 == "s1"? Вы можете сделать это, передав аргументы другой функции макроса. Но есть ли прямой путь?

Ответ 1

Если это обе строки, вы можете просто:

#define STR3 STR1 STR2

Препроцессор автоматически объединяет соседние строки.

EDIT:

Как отмечено ниже, это не препроцессор, а компилятор, который выполняет конкатенацию.

Ответ 2

Вам не нужно такое решение для строковых литералов, поскольку они объединяются на уровне языка, и в любом случае оно не будет работать, потому что "s" "1" не является допустимым токеном препроцессора.

[Редактировать: В ответ на неправильный комментарий "Только для записи" ниже, который, к сожалению, получил несколько голосов, я повторю приведенное выше утверждение и заметлю, что фрагмент программы

#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")

выдает это сообщение об ошибке на этапе предварительной обработки gcc: error: вставка "s" и "" 1 "" не дает действительный токен предварительной обработки

]

Однако для общего вставки токена попробуйте следующее:

/*
 * Concatenate preprocessor tokens A and B without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define PPCAT_NX(A, B) A ## B

/*
 * Concatenate preprocessor tokens A and B after macro-expanding them.
 */
#define PPCAT(A, B) PPCAT_NX(A, B)

Затем, например, PPCAT_NX(s, 1) и PPCAT(s, 1) генерируют идентификатор s1, если s не определен как макрос, и в этом случае PPCAT(s, 1) выдает <macro value of s>1.

Продолжаем тему следующих макросов:

/*
 * Turn A into a string literal without expanding macro definitions
 * (however, if invoked from a macro, macro arguments are expanded).
 */
#define STRINGIZE_NX(A) #A

/*
 * Turn A into a string literal after macro-expanding it.
 */
#define STRINGIZE(A) STRINGIZE_NX(A)

Затем

#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"

В отличие от

STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"

#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"

Ответ 3

Подсказка: макрос STRINGIZE - это классно, но если вы допустили ошибку, а его аргумент не является макросом - у вас была опечатка в имени или забыли #include заголовочный файл - тогда компилятор будет счастливо помещать имя якобы макроса в строку без ошибок.

Если вы предполагаете, что аргумент STRINGIZE всегда является макросом с нормальным значением C, тогда

#define STRINGIZE(A) ((A),STRINGIZE_NX(A))

будет расширять его один раз и проверять его на достоверность, отменить это, а затем развернуть его снова в строку.

Мне потребовалось некоторое время, чтобы понять, почему STRINGIZE(ENOENT) заканчивается как "ENOENT" вместо "2"... Я не включил errno.h.