Spec-Zone.ru › GCC 9 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-9.5.0/cpp/Concatenation.html

Spec-Zone.ru

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