Spec-Zone.ru › GCC 4 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 },
  ...
};

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

Spec-Zone.ru

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