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