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.
Рассмотрим (как в C99 подпункте 6.7.5 абзац 4) объявление 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», приведенных выше, пока не поддерживается.
Для совместимости с существующим кодом, написанным для версий компилятора, в которых атрибуты для вложенных деклараторов не были реализованы, допускается некоторая свобода в размещении атрибутов. Если атрибут, который применяется только к типам, применяется к декларации, он обрабатывается как применяемый к типу этой декларации. Если атрибут, который применяется только к декларациям, применяется к типу декларации, он обрабатывается как применяемый к этой декларации; и для совместимости с кодом, размещающим атрибуты непосредственно перед идентификатором, объявленным, такой атрибут, применённый к типу возвращаемого значения функции, обрабатывается как применяемый к типу функции, а такой атрибут, применённый к типу элемента массива, обрабатывается как применяемый к типу массива. Если атрибут, который применяется только к типам функций, применяется к типу указателя на функцию, он обрабатывается как применяемый к типу целевого указателя; если такой атрибут применяется к типу возвращаемого значения функции, который не является указателем на функцию, он обрабатывается как применяемый к типу функции.
Далее: Функции-прототипы, Предыдущее: Атрибуты операторов, Вверх: Расширения C [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/Attribute-Syntax.html