6.39 Синтаксис атрибутов ¶
В этом разделе описывается синтаксис, с помощью которого __attribute__ можно использовать, а также конструкции, к которым привязываются спецификаторы атрибутов для языка C. Некоторые детали могут отличаться для C++, Objective-C. Из-за недостатков в грамматике атрибутов, некоторые формы, описанные здесь, могут не быть успешно распарсены во всех случаях.
Существуют некоторые проблемы с семантикой атрибутов в C++. Например, нет привязок для атрибутов, хотя они могут влиять на генерацию кода, поэтому могут возникнуть проблемы при использовании атрибутированных типов совместно с шаблонами или перегрузкой. Аналогично, typeid не различает типы с различными атрибутами. Поддержка атрибутов в C++ может быть ограничена в будущем атрибутами только для объявлений, но не для вложенных деклараторов.
См. Объявление атрибутов функций для подробностей семантики атрибутов, применяемых к функциям. См. Указание атрибутов переменных для подробностей семантики атрибутов, применяемых к переменным. См. Указание атрибутов типов для подробностей семантики атрибутов, применяемых к структурам, объединениям и перечислениям. См. Атрибуты меток для подробностей семантики атрибутов, применяемых к меткам. См. Атрибуты перечислителей для подробностей семантики атрибутов, применяемых к перечислителям. См. Атрибуты операторов для подробностей семантики атрибутов, применяемых к операторам.
Спецификатор атрибута имеет вид __attribute__ ((attribute-list)). Список атрибутов — это, возможно, пустая последовательность атрибутов, разделённых запятыми, где каждый атрибут — один из следующих:
- Пустой. Пустые атрибуты игнорируются.
- Имя атрибута (которое может быть идентификатором, например,
unused, или служебным словом, например,const). - Имя атрибута, за которым следует список параметров в скобках для атрибута. Эти параметры принимают один из следующих видов:
- Идентификатор. Например, атрибуты
modeиспользуют этот вид. - Идентификатор, за которым следует запятая и непустой список выражений, разделённых запятыми. Например, атрибуты
formatиспользуют эту форму. - Возможный пустой список выражений, разделённых запятыми. Например, атрибуты
format_argиспользуют эту форму со списком, являющимся единственным целочисленным константным выражением, и атрибутыaliasиспользуют эту форму со списком, являющимся единственной строковой константой.
- Идентификатор. Например, атрибуты
Список спецификаторов атрибутов — это последовательность одного или нескольких спецификаторов атрибутов, не разделённых никакими другими токенами.
Вы можете необязательно указать имена атрибутов с «__» перед и после имени. Это позволяет использовать их в заголовочных файлах, не беспокоясь о возможной макрокоманде с тем же именем. Например, можно использовать имя атрибута __noreturn__ вместо noreturn.
Атрибуты меток ¶
В GNU C, список спецификаторов атрибутов может появиться после двоеточия, следующего за меткой, отличной от case или default метки. GNU C++ допускает атрибуты на метках только в том случае, если спецификатор атрибута непосредственно следует за точкой с запятой (т. е. метка применяется к пустому оператору). Если точка с запятой отсутствует, атрибуты меток C++ являются неоднозначными, так как в C++ допускается маркирование объявления, которое может начинаться со списка атрибутов. Объявления не могут быть помечены в C90 или C99, поэтому неоднозначность не возникает.
Атрибуты перечислителей ¶
В GNU C, список спецификаторов атрибутов может появиться в качестве части перечислителя. Атрибут следует за константой перечисления, перед =, если она есть. Необязательный атрибут в перечислителе относится к константе перечисления. Невозможно разместить атрибут после константного выражения, если оно есть.
Атрибуты операторов ¶
В GNU C, список спецификаторов атрибутов может появиться в качестве части пустого оператора. Атрибут предшествует точке с запятой.
Атрибуты типов ¶
Список спецификаторов атрибутов может появиться в качестве части спецификатора struct, union или enum. Он может идти непосредственно после ключевого слова struct, union или enum, или после закрывающей фигурной скобки. Первый синтаксис предпочтительнее. В тех случаях, когда спецификаторы атрибутов следуют за закрывающей фигурной скобкой, они рассматриваются как относящиеся к определённой структуре, объединению или перечислению, а не к любому окружающему объявлению, в котором появляется спецификатор типа, и тип, определённый, не считается полным до спецификаторов атрибутов.
Все остальные атрибуты ¶
В противном случае спецификатор атрибута появляется в качестве части объявления, включая объявления безымянных параметров и имён типов, и относится к этому объявлению (которое может быть вложено в другое объявление, например, в случае объявления параметра), или к определённому декларатору в объявлении. Когда спецификатор атрибута применяется к параметру, объявленному как функция или массив, он должен применяться к функции или массиву, а не к указателю, в который параметр неявно преобразуется, но это пока не реализовано должным образом.
Любой список спецификаторов и квалификаторов в начале объявления может содержать спецификаторы атрибутов, независимо от того, может ли такой список в этом контексте содержать спецификаторы класса хранения. (Однако некоторые атрибуты по существу являются спецификаторами класса хранения и имеют смысл только там, где могут использоваться спецификаторы класса хранения; например, section.) Существует одно необходимое ограничение для этого синтаксиса: первое объявление параметра старого стиля в определении функции не может начинаться со спецификатора атрибута, так как такой атрибут относится к функции вместо этого с помощью синтаксиса, описанного ниже (который, однако, пока не реализован в этом случае). В некоторых других случаях спецификаторы атрибутов разрешены по этой грамматике, но пока не поддерживаются компилятором. Все спецификаторы атрибутов в этом месте относятся к объявлению в целом. В устаревшем использовании, где тип int подразумевается отсутствием спецификаторов типа, такой список спецификаторов и квалификаторов может быть списком спецификаторов атрибутов без других спецификаторов или квалификаторов.
В настоящее время первый параметр в прототипе функции должен иметь какой-либо спецификатор типа, который не является спецификатором атрибута; это разрешает неоднозначность в интерпретации void f(int
(__attribute__((foo)) x)), но может быть изменено. В настоящее время, если круглые скобки декларатора функции содержат только атрибуты, эти атрибуты игнорируются, а не приводят к ошибке или предупреждению или подразумевают один параметр типа int, но это может быть изменено.
Список спецификаторов атрибутов может появиться непосредственно перед декларатором (кроме первого) в списке деклараторов, разделённых запятыми, в объявлении более чем одного идентификатора с использованием одного списка спецификаторов и квалификаторов. Такие спецификаторы атрибутов применяются только к идентификатору, перед декларатором которого они появляются. Например, в
__attribute__((noreturn)) void d0 (void),
__attribute__((format(printf, 1, 2))) d1 (const char *, ...),
d2 (void);
атрибут noreturn применяется ко всем объявленным функциям; атрибут format применяется только к d1.
Список спецификаторов атрибутов может появиться непосредственно перед запятой, = или точкой с запятой, завершающей объявление идентификатора, отличного от определения функции. Такие спецификаторы атрибутов применяются к объявленному объекту или функции. Когда указано имя сборки для объекта или функции (см. Управление именами, используемыми в коде ассемблера), атрибут должен следовать за спецификацией asm.
В будущем список спецификаторов атрибутов может быть разрешён после декларатора в определении функции (перед любыми объявлениями параметров старого стиля или телом функции).
Спецификаторы атрибутов могут быть смешаны с квалификаторами типов, появляющимися внутри [] декларатора массива параметра, в конструкции C99, посредством которой такие квалификаторы применяются к указателю, в который неявно преобразуется массив. Такие спецификаторы атрибутов применяются к указателю, а не к массиву, но в настоящее время это не реализовано и они игнорируются.
Список спецификаторов атрибутов может появиться в начале вложенного декларатора. В настоящее время существуют некоторые ограничения в этом использовании: атрибуты правильно применяются к декларатору, но для большинства отдельных атрибутов подразумеваемая семантика не реализована. Когда спецификаторы атрибутов следуют за * декларатора указателя, они могут быть смешаны с любыми присутствующими квалификаторами типов. Следующее описывает формальную семантику этого синтаксиса. Это имеет наибольший смысл, если вы знакомы с формальной спецификацией деклараторов в стандарте ISO C.
Рассмотрим (как в подпункте 6.7.5 абзаца 4 стандарта C99) объявление T
D1, где T содержит спецификаторы объявления, которые задают тип Type (такой как int), а D1 — это декларатор, содержащий идентификатор ident. Тип, указанный для ident для производных деклараторов, тип которых не включает спецификатор атрибута, указан в стандарте ISO C.
Если D1 имеет вид ( attribute-specifier-list D ), и объявление T D задаёт тип “derived-declarator-type-list Type” для ident, то T D1 задаёт тип “derived-declarator-type-list attribute-specifier-list Type” для ident.
Если D1 имеет вид *
type-qualifier-and-attribute-specifier-list D, и объявление T D указывает тип «derived-declarator-type-list Type» для ident, то T D1 указывает тип «derived-declarator-type-list type-qualifier-and-attribute-specifier-list указатель на Type» для ident.
Например,
void (__attribute__((noreturn)) ****f) (void);
указывает тип «указатель на указатель на указатель на указатель на функцию без возвращаемого значения, возвращающую void». В качестве другого примера,
char *__attribute__((aligned(8))) *f;
указывает тип «указатель на 8-байтовый выровненный указатель на char». Обратите внимание, что это не работает со многими атрибутами; например, использование атрибутов ‘aligned’ и ‘noreturn’, приведенных выше, пока не поддерживается.
Для совместимости со существующим кодом, написанным для версий компилятора, которые не реализовывали атрибуты для вложенных деклараторов, допускается некоторая свобода в размещении атрибутов. Если атрибут, который применяется только к типам, применяется к объявлению, он обрабатывается как применяющийся к типу этого объявления. Если атрибут, который применяется только к объявлениям, применяется к типу объявления, он обрабатывается как применяющийся к этому объявлению; и, для совместимости с кодом, размещающим атрибуты непосредственно перед идентификатором объявленного элемента, такой атрибут, применённый к типу возвращаемого значения функции, обрабатывается как применяющийся к типу функции, и такой атрибут, применённый к типу элемента массива, обрабатывается как применяющийся к типу массива. Если атрибут, который применяется только к типам функций, применяется к типу указателя на функцию, он обрабатывается как применяющийся к типу целевого указателя; если такой атрибут применяется к типу возвращаемого значения функции, который не является типом указателя на функцию, он обрабатывается как применяющийся к типу функции.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/Attribute-Syntax.html