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-5.5.0/cpp/Concatenation.html