Spec-Zone.ru › GCC 12 CPP

3.5 Конкатенация

Часто бывает полезно объединить два токена в один при развёртывании макросов. Это называется склеиванием токенов или конкатенацией токенов. Оператор предварительной обработки «##» выполняет склеивание токенов. При развёртывании макроса два токена по обе стороны каждого оператора «##» объединяются в один токен, который затем заменяет оператор «##» и два исходных токена в развёртывании макроса. Обычно оба будут идентификаторами, или один будет идентификатором, а другой — препроцессорным числом. При склеивании они образуют более длинный идентификатор. Это не единственный допустимый случай. Также можно конкатенировать два числа (или число и имя, например 1.5 и e3) в число. Кроме того, многосимвольные операторы, такие как +=, могут быть сформированы путём склеивания токенов.

Однако два токена, которые вместе не образуют допустимого токена, не могут быть склеены вместе. Например, вы не можете конкатенировать x с + ни в каком порядке. Если вы попытаетесь, препроцессор выдаст предупреждение и выведет два токена. Определено ли, будет ли пробел между токенами, не определено. Часто встречаются ненужные применения «##» в сложных макросах. Если вы получаете это предупреждение, вероятно, можно просто удалить «##».

Оба токена, объединённые с помощью «##», могут происходить из тела макроса, но вы также могли бы написать их как один токен в первую очередь. Склеивание токенов наиболее полезно, когда один или оба токена происходят из аргумента макроса. Если любой из токенов рядом с «##» является именем параметра, оно заменяется его фактическим аргументом перед выполнением «##». Как и при преобразовании в строку, фактический аргумент не развёртывается макросом в первую очередь. Если аргумент пустой, «##» не имеет эффекта.

Помните, что C-препроцессор преобразует комментарии в пробелы до обработки макросов. Поэтому вы не можете создать комментарий, склеивая «/» и «*». Вы можете вставить любое количество пробелов между «##» и его операндами, включая комментарии, и вы можете вставить комментарии в аргументы, которые будут склеиваться. Однако это ошибка, если «##» появляется в начале или конце тела макроса.

Рассмотрим C-программу, которая интерпретирует именованные команды. Возможно, требуется таблица команд, например, массив структур, объявленных следующим образом:

struct command
{
  char *name;
  void (*function) (void);
};
struct command commands[] =
{
  { "quit", quit_command },
  { "help", help_command },
  …
};

Было бы удобнее не нужно было бы указывать имя каждой команды дважды, один раз в строковой константе и один раз в имени функции. Макрос, принимающий имя команды в качестве аргумента, может сделать это излишним. Строковую константу можно создать с помощью stringizing, а имя функции — путём конкатенации аргумента со строкой «_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-12.1.0/cpp/Concatenation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API