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