3.5 Конкатенация ¶
Часто бывает полезно объединить два токена в один при разворачивании макроса. Это называется склеиванием токенов или конкатенацией токенов. Оператор предварительной обработки ‘##’ выполняет склеивание токенов. При разворачивании макроса два токена по обе стороны оператора ‘##’ объединяются в один токен, который затем заменяет оператор ‘##’ и два исходных токена в расширении макроса. Обычно оба будут идентификаторами, или один будет идентификатором, а другой — числом предварительной обработки. При склеивании они образуют более длинный идентификатор. Это не единственный допустимый случай. Также можно склеить два числа (или число и имя, например 1.5 и e3) в одно число. Также с помощью склеивания токенов можно образовать многосимвольные операторы, например +=.
Однако, два токена, которые вместе не образуют допустимый токен, нельзя склеить. Например, вы не можете склеить x с + в любом порядке. Если вы попытаетесь это сделать, препроцессор выдаст предупреждение и выведет два токена. Будет ли вставлено пробельное пространство между токенами, не определено. Часто встречаются ненужные случаи использования ‘##’ в сложных макросах. Если вы получаете это предупреждение, скорее всего, можно просто удалить ‘##’.
Оба токена, объединённые с помощью ‘##’, могут происходить из тела макроса, но вы могли бы написать их и как один токен с самого начала. Склеивание токенов наиболее полезно, когда один или оба токена происходят из аргумента макроса. Если один из токенов рядом с ‘##’ является именем параметра, оно заменяется его фактическим аргументом перед выполнением ‘##’. Как и при строковом преобразовании, фактический аргумент не расширяется макросом предварительно. Если аргумент пустой, ‘##’ не оказывает никакого влияния.
Помните, что C-препроцессор преобразует комментарии в пробелы до обработки макросов. Поэтому вы не можете создать комментарий, склеивая ‘/’ и ‘*’. Вы можете поместить любое количество пробелов между ‘##’ и его операндами, включая комментарии, и вы можете разместить комментарии в аргументах, которые будут склеены. Однако ошибка, если ‘##’ появляется в начале или в конце тела макроса.
Рассмотрим C-программу, которая интерпретирует именованные команды. Вероятно, потребуется таблица команд, возможно, массив структур, объявленных следующим образом:
struct command
{
char *name;
void (*function) (void);
};struct command commands[] =
{
{ "quit", quit_command },
{ "help", help_command },
…
};Было бы удобнее не указывать каждое имя команды дважды, один раз в строковой константе и один раз в имени функции. Макрос, принимающий имя команды в качестве аргумента, может сделать это ненужным. Строковая константа может быть создана с помощью строкового преобразования, а имя функции — путём конкатенации аргумента с ‘_command’. Вот как это делается:
#define COMMAND(NAME) { #NAME, NAME ## _command }
struct command commands[] =
{
COMMAND (quit),
COMMAND (help),
…
};
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/cpp/Concatenation.html